为什么Go不允许获取地图值的地址?

use*_*097 1 dictionary pointers go

这与为什么禁止获取(&)地图成员的地址,但允许(&)切片元素相同?但我对接受的答案不满意:"切片由支持数组支持,地图不支持."

注意:我现在已经在上面引用的问题中添加了我自己的答案.

问题访问结构的地图(不复制),甚至更好,但其接受的答案说,你不能修改结构值的字段中的地图,因为你不能把它的地址(这是我的问题).

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

那么为什么我不能获取地图值的地址的真正原因是什么?

我想修改一个map struct值.可以使用++或+ =等运算符来修改映射中的数值

     func icandothis() {
        cmap := make(map[int]complex64)
        cmap[1] += complex(1, 0)
        fmt.Println(cmap[1])
     }
Run Code Online (Sandbox Code Playgroud)

但是结构值不能修改:

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

}
Run Code Online (Sandbox Code Playgroud)

pet*_*rSO 14

让我们从这个错误的主张开始:

我想修改一个map struct值.可以使用++或+ =等运算符来修改映射中的数值

 func icandothis() {
    cmap := make(map[int]complex64)
    cmap[1] += complex(1, 0)
    fmt.Println(cmap[1])
 }
Run Code Online (Sandbox Code Playgroud)

让我们扩展速记形式:

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()
}
Run Code Online (Sandbox Code Playgroud)

游乐场:https://play.golang.org/p/1OgmI_AD9uN

输出:

(1+0i)
(1+0i)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的icandothisLong(),扩展形式icandothisShort(),没有就地更新.



下一个虚假声明,

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

那么为什么我不能获取地图值的地址的真正原因是什么?


真正的原因是你不了解地图数据结构.

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

做一些基础研究.例如,

GopherCon 2016:Keith Randall - 在地图实施中

  • 我已更正,cmap[1] += complex(1,0) 不会“修改”适当的映射元素,但良好的编译器实现不应评估 cmap[1] 两次,正如规范所述。至于我对地图实现的无知,尤其是对垃圾收集实现的无知,我不会接受我的缺乏知识作为答案。 (2认同)

归档时间:

查看次数:

1053 次

最近记录:

7 年,6 月 前