代码之家  ›  专栏  ›  技术社区  ›  RudziankoÅ­

指针和循环片段[重复]

  •  0
  • RudziankoÅ­  · 技术社区  · 7 年前

    这个问题已经有了答案:

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

    我有以下代码:

    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
    }
    

    https://play.golang.org/p/65Le_8Pi3Mi

    唯一的区别是切片语义 []*string []string 它如何改变 cmd 变数?你能通过两个循环详细地描述或解释一下在迭代过程中内存中发生了什么吗?

    2 回复  |  直到 7 年前
        1
  •  4
  •   Zak    7 年前

    当你打电话 range 在集合上,go运行时初始化两个内存位置;一个用于索引(在本例中 _ )和一个值 cmd 是的。

    那么,range的作用是获取集合中的每个项目 将它们复制到调用时创建的内存位置 范围 是的。

    这意味着片中的每一个项都被一个一个地放入那个内存位置。

    当你这样做的时候 &cmd 你在拿一个指针。此指针指向每个切片项要复制到的共享内存位置。

    使用创建的所有指针 &命令 都指向同一个内存位置。

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

    这就是为什么你得到输出

    update
    update
    update
    
        2
  •  1
  •   Himanshu    7 年前

    这是因为在一种情况下,您将地址传递给struct,而在另一种情况下,您将传递字符串值。因此,每当将Stutt字段附加到一个切片时,它将在同一地址上更新现有值。这就是为什么只获取结构的指针类型切片的最后一个值,即 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 将指向同一地址,该地址在每次迭代中将其值更新到同一位置,而不是将地址传递给 cmd 在里面 loop1 是的。

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

    slice := make([]obj, 0, 0)
    

    所以当你在上面循环时,你实际上是在传递 命令 并将其分配给指针字段。

    要查看差异,请打印类型,然后您将获得以下信息:

    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)
    }
    

    Playground example

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

    // []*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 包含指向 string 是的。它们都是不同的情况。使用 fmt 包以查看在中创建的切片的实际类型 回路1 功能

    Playground example