This question already has answers here:
Why do I get a “cannot assign” error when setting value to a struct as a value in a map? [duplicate]
(2个答案)
Why does Go forbid taking the address of (&) map member, yet allows (&) slice element?
(2个答案)
2年前关闭。
这与Why does go forbid taking the address of (&) map member, yet allows (&) slice element?相同,但是我对公认的答案不满意:“slice 由后备数组支持,而映射则不支持。”
问题Access Struct in Map (without copying)甚至更好,但是它被接受的答案是说您不能修改映射中struct值的字段,因为您不能获取其地址(这是我的问题)。
就像 slice 一样,映射由内存结构(可能包括数组)支持。
那么,为什么我不能接受 map 值的地址的真正原因是什么?
我想就地修改 map 结构值。可以使用++或+ =等运算符在 map 上修改数字值
但是结构值不能修改:
输出:
下一个误解
存储桶存储结构支持 map 。映射键通过不完美的动态哈希标识当前的主存储桶。映射键和值存储在主存储桶或溢出存储桶中。随着创建,更新和删除 map 条目, map 存储区会不断进行重组。
map 条目在内存中没有固定的位置。
这是有关 map 工作方式的相当详细的说明:
GopherCon 2016: Keith Randall - Inside the Map Implementation
(2个答案)
Why does Go forbid taking the address of (&) map member, yet allows (&) slice element?
(2个答案)
2年前关闭。
这与Why does go forbid taking the address of (&) map member, yet allows (&) slice element?相同,但是我对公认的答案不满意:“slice 由后备数组支持,而映射则不支持。”
问题Access Struct in Map (without copying)甚至更好,但是它被接受的答案是说您不能修改映射中struct值的字段,因为您不能获取其地址(这是我的问题)。
就像 slice 一样,映射由内存结构(可能包括数组)支持。
那么,为什么我不能接受 map 值的地址的真正原因是什么?
我想就地修改 map 结构值。可以使用++或+ =等运算符在 map 上修改数字值
func icandothis() {
cmap := make(map[int]complex64)
cmap[1] += complex(1, 0)
fmt.Println(cmap[1])
}
但是结构值不能修改:
type Complex struct {
R float32
I float32
}
func (x *Complex) Add(c Complex) {
x.R += c.R
x.I += c.I
}
func but_i_cannot_do_this() {
cmap := make(map[int]Complex)
//cmap[1].Add(Complex{1, 0})
fmt.Println(cmap[1])
}
func so_i_have_to_do_this() {
cmap := make(map[int]Complex)
c := cmap[1]
c.Add(Complex{1, 0})
cmap[1] = c
fmt.Println(cmap[1])
}
最佳答案
让我们从这个误解开始:
让我们扩展简写形式:
package main
import (
"fmt"
)
func icandothisShort() {
cmap := make(map[int]complex64)
cmap[1] += complex(1, 0)
fmt.Println(cmap[1])
}
func icandothisLong() {
cmap := make(map[int]complex64)
// An assignment operation x op= y where op is a binary arithmetic operator
// is equivalent to x = x op (y) but evaluates x only once.
// cmap[1] += complex(1, 0)
v := cmap[1] // v = zero value = complex(0, 0)
v = v + complex(1, 0) // v = complex(0, 0) + complex(1, 0) = complex(1, 0)
cmap[1] = v // cmap[1] = v = complex(1, 0)
a := cmap[1] // a = complex(1, 0)
fmt.Println(a) // complex(1, 0)
}
func main() {
icandothisShort()
icandothisLong()
}
游乐场:https://play.golang.org/p/1OgmI_AD9uN输出:
(1+0i)
(1+0i)
正如您在icandothisLong()
的扩展形式icandothisShort()
中看到的那样,没有就地更新。下一个误解
存储桶存储结构支持 map 。映射键通过不完美的动态哈希标识当前的主存储桶。映射键和值存储在主存储桶或溢出存储桶中。随着创建,更新和删除 map 条目, map 存储区会不断进行重组。
map 条目在内存中没有固定的位置。
这是有关 map 工作方式的相当详细的说明:
GopherCon 2016: Keith Randall - Inside the Map Implementation
关于pointers - 为什么Go不允许使用 map 值地址? [复制],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49202077/