这与为什么为什么不接受(&)映射成员的地址而允许(&)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])
}
让我们从这个虚假的声明开始:
我想就地修改地图结构值。可以使用++或+ =等运算符在适当的位置修改地图中的数值
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-地图实施内部
问题内容: Go不允许使用地图成员的地址: 理由是,如果Go允许使用此地址,则当地图后备存储增长或减少时,该地址可能变得无效,从而使用户感到困惑。 但是,当Go slice超出其容量时,它将被重新定位,但是Go允许我们获取slice元素的地址: 为什么Go这样设计?切片元素的地址有何特殊之处? 问题答案: 切片和贴图之间的主要区别在于:切片由后备数组支持,而贴图则没有。 如果地图增大或缩小,则指向
在Java9中,为、和接口引入了新的工厂方法。这些方法允许在一行中快速实例化具有值的Map对象。现在,如果我们考虑: 以上内容是允许的,没有任何例外,如果我们这样做: 我知道HashMap可以将null作为键和值,但为什么在Map.of的情况下会受到限制呢? 同样的情况也发生在和中。
我正在阅读jls§5.1.7,它说有9种拳击类型,第9种是拳击 然后我读到的拆箱转换会抛出一个。好的,这很明显。那么为什么的装箱不会抛出一个以及装箱值有什么用呢?
问题内容: 如JDK文档中所指定,Hashtable不允许空键或值。HashMap允许一个null键和任意数量的null值。为什么是这样? 问题答案: Hashtable是较老的类,通常不鼓励使用Hashtable。也许他们看到了对null键的需求,更重要的是对null值的需求,并将其添加到HashMap实现中。 HashMap是较新的,并且具有更高级的功能,这些基本上只是对Hashtable功能
问题内容: 我刚接触PHP,但是多年来我一直在使用类似的语言进行编程。我被以下内容弄糊涂了: 它产生了语法错误:这就是调用。 但这很好用: 碰了一会儿之后,我被告知您不能在默认属性中调用函数。你必须在做。我的问题是:为什么?这是“功能”还是草率的实现?有什么根据? 问题答案: 编译器代码建议这是设计使然,尽管我不知道其背后的官方原因是什么。我也不确定要可靠地实现此功能需要花费多少精力,但是目前完成
问题内容: 来自C语言的Go语言最值得注意的方面之一是,如果在其中声明了一个未使用的变量,编译器将不会编译您的程序。那么,如果在函数中声明了一个未使用的参数,那么为什么要构建此程序呢? 问题答案: 没有正式的原因,但是在golang-nuts上给出的原因是: 未使用的变量始终是编程错误,而编写不使用其所有参数的函数是很常见的。 可以将这些参数保留为未命名(使用_),但这可能会与诸如 func fo