修改的切片元素无法通过map访问。我做错了什么?

huangapple go评论88阅读模式
英文:

Modified slice elements not accessible with map. What am I doing wrong?

问题

我有一个切片,其中包含一个或多个复杂结构体的元素,我希望通过一个映射来访问该切片的所有元素。这个映射包含指向切片元素的指针。我的问题是,当我更改切片元素的内容时,映射指向该元素的内容不会反映出来。也就是说,如果我从切片中访问更改后的元素,我可以看到变化。但是,如果我从映射中访问该元素,我看不到变化。

我在下面给出了一个抽象的代码示例。在这个示例中,情况变得更加奇怪,因为我只看到一个元素的变化,尽管所有元素都应该被更改。

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
英文:

I have a slice of a more or less complex struct and I want all elements of this slice to be accessible with a map. The map contains pointers to the slice elements. My problem is now that when I change the content of a slice element, it is not reflected in the map pointing to this element. I.e. If I access the changed elements from the slice, I see the changes. If I however access the element from my map, I don't see the change.

I made an abstract code example you'll find below. Here it gets even more strange since I see the change in one element although all should be changed.

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

The output is:

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

得分: 1

我会为你翻译以下内容:

我只会一直在切片和映射中使用指针。这样可以简化很多事情。

由于你正在使用值的切片,所以在append操作之后,&t[i]变成了指向旧切片中元素的指针。当你访问它时,你实际上是在访问旧切片的元素。因此,映射引用的是旧切片的元素。

使用指针可以解决这个问题,因为每个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)
    }
}

输出结果为:

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

你可以在这里查看代码和运行结果:https://play.golang.org/p/KvG3Mj4v1u

英文:

I would just consistently use pointers in slices and maps. That simplifies a lot.

As you are using slices of values, it happens that &t[i] after append operation becomes a pointer to an element in the old discarded slice. When you accessing it you are accessing the element of the old slice. Therefore map is referencing an element of a old slice.

Using pointers solves the problem because there is only one copy of each Test structure and multiple pointers to them. It does not matter whether the pointers are in old slice, new slice or map.

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

The output is

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

huangapple
  • 本文由 发表于 2015年3月5日 21:46:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/28879323.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定