Loops 指针和循环的切片

Loops 指针和循环的切片,loops,pointers,go,slice,Loops,Pointers,Go,Slice,我想这个问题问了好几次,但我还是很困惑: 我有以下代码: type obj struct { s *string } var cmdsP = []*string { stringPointer("create"), stringPointer("delete"), stringPointer("update"), } var cmds = []string { "create", "delete", "update", } // []

我想这个问题问了好几次,但我还是很困惑:

我有以下代码:

type obj struct {
    s *string
}

var cmdsP = []*string {
    stringPointer("create"),
    stringPointer("delete"),
    stringPointer("update"),
}

var cmds = []string {
    "create",
    "delete",
    "update",
}

// []*string
func loop1() {
    slice := make([]obj, 0, 0)

    for _, cmd := range cmdsP {
        slice = append(slice, obj{cmd})
    }
    for _, o := range slice {
        fmt.Println(*o.s)
    }
}

// []string
func loop2() {
    slice := make([]obj, 0, 0)
    for _, cmd := range cmds {
        slice = append(slice, obj{&cmd})
    }
    for _, o := range slice {
        fmt.Println(*o.s)
    }
}

func stringPointer(v string) *string {
    return &v
}


唯一的区别在于slice semantic
[]*string
[]string
如何改变
cmd
变量的行为?您能详细地画出或解释一下在两个循环的迭代过程中内存中发生了什么吗

在集合上调用
range
时,go运行时初始化2个内存位置;一个用于索引(在本例中为
),一个用于值
cmd

然后,range所做的是获取集合中的每个项,并将它们复制到调用
range
时创建的内存位置

这意味着片中的每个项都被逐个放入该内存位置

当您执行
&cmd
时,您正在使用指针。该指针指向每个切片项要复制到的共享内存位置

使用
&cmd
创建的所有指针都指向相同的内存位置

这意味着在
范围
完成后,指针指向的内存位置中剩下的唯一值是
范围
迭代中的最后一个值

这就是您获得输出的原因

update
update
update

这是因为在一种情况下,您将向struct传递地址,而在另一种情况下,您将传递字符串值。因此,每当您将结构字段附加到切片时,它都将更新同一地址上的现有值。这就是为什么您只得到结构的指针类型切片的最后一个值,在本例中是
update

// []string
func loop2() {
    slice := make([]obj, 0, 0)
    for _, cmd := range cmds {
        slice = append(slice, obj{&cmd})
    }
    for _, o := range slice {
        fmt.Println(*o.s)
    }
}
&cmd
将指向同一地址,该地址在每次迭代中将其值更新到同一位置,而在
loop1
中将地址传递给
cmd
时,情况并非如此

已编辑 这是
[]obj
的一个片段,它有一个指针类型*字符串的字段

slice := make([]obj, 0, 0)
因此,当您在其上循环时,实际上是在传递
cmd
的地址,并将其分配给指针字段

要查看差异,请打印类型,您将获得例如的信息:

func loop1() {
    slice := make([]string, 0, 0)

    for _, cmd := range cmdsP {
        slice = append(slice, *cmd)
    }
    for _, o := range slice {
        fmt.Println(o)
    }

    fmt.Printf("%#v\n", slice)
}

在上面的例子中,您正在创建一段字符串

// []*string
func loop1() {
    slice := make([]obj, 0, 0)

    for _, cmd := range cmdsP {
        slice = append(slice, obj{cmd})
    }
    for _, o := range slice {
        fmt.Println(*o.s)
    }
    fmt.Printf("%#v\n", slice)
}
在第二种情况下,您正在创建一个
obj
struct的切片,其中包含指向
string
的指针字段。它们都是不同的情况。使用
fmt
package查看在
loop1
函数中创建的实际切片类型


谢谢您的回答!您说过
,所以每当您将结构字段附加到切片时
,但如果我附加字符串字段
切片:=make([]string,0,0)
一切正常。有什么区别@请检查编辑后的答案