切片指针和循环[重复]

Posted

技术标签:

【中文标题】切片指针和循环[重复]【英文标题】:Slice of pointers and loop [duplicate] 【发布时间】:2018-12-20 18:43:23 【问题描述】:

我认为这个问题被问了好几次,但我仍然感到困惑:

我有以下代码:

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, objcmd)
    
    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 变量的行为?您能否详细说明或详细说明在通过两个循环进行迭代期间内存中发生的情况?

【问题讨论】:

【参考方案1】:

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

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

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

当您执行&cmd 时,您将获得一个指针。该指针指向每个切片项被复制到的共享内存位置。

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

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

这就是你得到输出的原因

update
update
update

【讨论】:

【参考方案2】:

这是因为在一种情况下,您将地址传递给 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)
    

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

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)

Playground example

在上述情况下,您正在创建一个字符串切片。

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

    for _, cmd := range cmdsP 
        slice = append(slice, objcmd)
    
    for _, o := range slice 
        fmt.Println(*o.s)
    
    fmt.Printf("%#v\n", slice)

而在第二种情况下,您正在创建 obj 结构的切片,其中包含指向 string 的指针字段。他们都是不同的情况。使用fmt 包查看您在loop1 函数中创建的切片的实际类型

Playground example

【讨论】:

感谢您的回答!你说So whenever you append an struct field to a slice 但如果我附加字符串字段slice := make([]string, 0, 0) 一切都很好。有什么区别? play.golang.org/p/7UdLlP2GiLw @Rudziankoŭ 请检查编辑后的答案

以上是关于切片指针和循环[重复]的主要内容,如果未能解决你的问题,请参考以下文章

字典列表中的切片[重复]

使用索引值列表对 pandas 多索引数据框进行切片 [重复]

循环中的C ++对象引用[重复]

具有重复值的 Python 多索引切片

删除单链表中的循环[重复]

Go-常识补充-切片-map(类似字典)-字符串-指针-结构体