修改后的切片元素无法通过地图访问我究竟做错了什么?

时间:2015-03-05 13:46:51

标签: dictionary go slice

我有一个或多或少复杂的结构片段,我希望可以使用地图访问此切片的所有元素。地图包含指向切片元素的指针。我现在的问题是,当我更改切片元素的内容时,它不会反映在指向此元素的地图中。即如果我从切片访问更改的元素,我会看到更改。但是,如果我从地图中访问该元素,我看不到更改。

我在下面找到了一个抽象代码示例。这里变得更加奇怪,因为我看到一个元素的变化虽然都应该改变。

package main

import "fmt"

type Test struct {
    one int
    two *string
}

type List []Test
type MapToList map[int]*Test

func MakeTest() (t List, mt MapToList) {

    t = []Test{}
    mt = make(map[int]*Test)

    var one, two, three string
    one = "one"
    two = "two"
    three = "three"

    t = append(t, Test{1, &one})
    mt[1] = &t[len(t)-1]
    t = append(t, Test{2, &two})
    mt[2] = &t[len(t)-1]
    t = append(t, Test{3, &three})
    mt[3] = &t[len(t)-1]

    return
}

func (s *List) Modify() {
    for index := range *s {
        var str string = "xxx"
        (*s)[index].two = &str
    }
}

func main() {

    t, mt := MakeTest()

    fmt.Println("Orginal")
    for index := range t{
        fmt.Println(index, t[index].one, *t[index].two)
    }

    t.Modify()  

    fmt.Println("Modified List")
    for index := range t{
        fmt.Println(index, t[index].one, *t[index].two)
    }

    fmt.Println("Modified Map")
    for key, value := range mt {
        fmt.Println(key, value.one, *value.two)
    }
}

输出结果为:

Orginal
0 1 one
1 2 two
2 3 three
Modified List
0 1 xxx
1 2 xxx
2 3 xxx
Modified Map
1 1 one
2 2 two
3 3 xxx

1 个答案:

答案 0 :(得分:1)

我会一直在切片和贴图中使用指针。这简化了很多。

当您使用值切片时,&t[i]操作后append成为指向旧丢弃切片中元素的指针。访问它时,您正在访问旧切片的元素。因此,map引用了旧切片的元素。

使用指针解决了这个问题,因为每个Test结构只有一个副本,并且有多个指针。指针是在旧切片,新切片还是映射中无关紧要。

package main

import "fmt"

type Test struct {
    one int
    two *string
}

type List []*Test
type MapToList map[int]*Test

func MakeTest() (t List, mt MapToList) {

    t = []*Test{}
    mt = make(map[int]*Test)

    var one, two, three string
    one = "one"
    two = "two"
    three = "three"

    t = append(t, &Test{1, &one})
    mt[1] = t[len(t)-1]
    t = append(t, &Test{2, &two})
    mt[2] = t[len(t)-1]
    t = append(t, &Test{3, &three})
    mt[3] = t[len(t)-1]

    return
}

func (s *List) Modify() {
    for index := range *s {
        var str string = "xxx"
        (*s)[index].two = &str
    }
}

func main() {

    t, mt := MakeTest()

    fmt.Println("Orginal")
    for index := range t{
        fmt.Println(index, t[index].one, *t[index].two)
    }

    t.Modify()  

    fmt.Println("Modified List")
    for index := range t{
        fmt.Println(index, t[index].one, *t[index].two)
    }

    fmt.Println("Modified Map")
    for key, value := range mt {
        fmt.Println(key, value.one, *value.two)
    }
}

https://play.golang.org/p/KvG3Mj4v1u

输出

Orginal
0 1 one
1 2 two
2 3 three
Modified List
0 1 xxx
1 2 xxx
2 3 xxx
Modified Map
1 1 xxx
2 2 xxx
3 3 xxx