duanguanya3052 2018-03-09 13: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 13: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条)
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部