duanguanya3052 2018-03-09 21:01
浏览 3
已采纳

为什么Go不允许使用地图值地址? [重复]

This is the same as Why does go forbid taking the address of (&) map member, yet allows (&) slice element? but I'm not satisfied with the accepted answer: "Slices are backed by a backing array and maps are not."

Note: I have now added my own answer to the referenced question above.

The question Access Struct in Map (without copying) is even better, but its accepted answer says you can't modify a field of a struct value in a map because you cannot take its address (which is my question).

Maps are backed by memory structures (possibly including arrays) just like slices are.

So what is the real reason why I can't take the address of a map value?

I wanted to modify a map struct value in place. Numeric values in maps can be modified in place using operators like ++ or +=

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

But struct values cannot be modified:

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

}
</div>
  • 写回答

2条回答 默认 最新

  • douchunsui2395 2018-03-09 21:36
    关注

    Let's start with this false claim:

    I wanted to modify a map struct value in place. Numeric values in maps can be modified in place using operators like ++ or +=

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

    Let's expand the shorthand form:

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

    Playground: https://play.golang.org/p/1OgmI_AD9uN

    Output:

    (1+0i)
    (1+0i)
    

    As you can see in icandothisLong(), the expanded form of icandothisShort(), there is no update in-place.



    The next false claim,

    Maps are backed by memory structures (possibly including arrays) just like slices are.

    So what is the real reason why I can't take the address of a map value?


    The real reason is that you don't understand the map data structure.

    Maps are backed by bucket memory structures. A map key, through an imperfect, dynamic hash, identifies a current primary bucket. The map keys and values are stored in the primary bucket or an overflow bucket. The map buckets are constantly reorganized as map entries are created, updated, and deleted. A map entry has no fixed location in memory.

    Do some basic research. For example,

    GopherCon 2016: Keith Randall - Inside the Map Implementation

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 三菱FX系列PLC串口指令
  • ¥15 cocos的js代码调用wx.createUseInfoButton问题!
  • ¥15 关于自相关函数法和周期图法实现对随机信号的功率谱估计的matlab程序运行的问题,请各位专家解答!
  • ¥15 Python程序,深度学习,有偿私
  • ¥15 扫描枪扫条形码出现问题
  • ¥35 poi合并多个word成一个新word,原word中横版没了.
  • ¥15 【火车头采集器】搜狐娱乐这种列表页网址,怎么采集?
  • ¥15 求MCSCANX 帮助
  • ¥15 机器学习训练相关模型
  • ¥15 Todesk 远程写代码 anaconda jupyter python3