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 上修改数字值
     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/

10-15 03:09
查看更多