一尘不染

为什么Go不允许使用地图值地址?

go

这与为什么为什么不接受(&)映射成员的地址而允许(&)slice元素相同?但我对接受的答案不满意:“切片由后备数组支持,而映射则不支持。”

注意:现在,我已对上面提到的问题添加了自己的答案。

Map中的Access Struct问题(不带复制)甚至更好,但是它被接受的答案是您不能修改map中的struct值字段,因为您无法获取其地址(这是我的问题)。

就像切片一样,映射由内存结构(可能包括数组)支持。

那么,为什么我不能使用映射值的地址的真正原因是什么?

我想就地修改地图结构值。可以使用++或+ =等运算符在适当的位置修改地图中的数值

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

}

阅读 228

收藏
2020-07-02

共1个答案

一尘不染

让我们从这个虚假的声明开始:

我想就地修改地图结构值。可以使用++或+ =等运算符在适当的位置修改地图中的数值

 func icandothis() {
    cmap := make(map[int]complex64)
    cmap[1] += complex(1, 0)
    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(),没有就地更新。



下一个虚假声明,

就像切片一样,映射由内存结构(可能包括数组)支持。

那么,为什么我不能使用映射值的地址的真正原因是什么?


真正的原因是您不了解地图数据结构。

存储桶存储结构支持地图。映射键通过不完美的动态哈希标识当前的主存储桶。映射键和值存储在主存储桶或溢出存储桶中。随着创建,更新和删除地图条目,地图存储区会不断进行重组。地图条目在内存中没有固定的位置。

做一些基础研究。例如,

GopherCon 2016:Keith Randall-地图实施内部

2020-07-02