duanlong4890 2018-03-07 08:56
浏览 57
已采纳

反映访问的地图不提供可修改的值

Context

In the process of writing a generic diff and patch algorithm I faced a problem with reflection in go.

When I'm trying to patch in a slice I have no problem, reflect.ValueOf(&slice).Elem().Index(0).CanSet() returns true. This allows me to patch anything inside the slice element, be it a slice of primitive or of structs.

Problem

However when I attempt this with a map reflect.ValueOf(&map).Elem().MapIndex(reflect.ValueOf("key")).CanSet() returns false. This prevents me from attempting to do anythnin with the content of my map.

Examples

Slice

s := []string{"a", "b", "c"}

v := reflect.ValueOf(&s).Elem()

e := v.Index(1)

println(e.String())
println(e.CanSet())
e.Set(reflect.ValueOf("d"))

for _, v := range s {
    print(v, " ")
}

output :
b
true
a d c

Map

m := map[string]string{
    "a": "1",
    "b": "2",
    "c": "3"}

mv := reflect.ValueOf(&m).Elem()
println(mv.MapIndex(reflect.ValueOf("a")).CanSet())

output:
false

How could I get a modifiable value out of a map through reflection?

Thanks for your time.

  • 写回答

1条回答 默认 最新

  • dp20011 2018-03-07 09:06
    关注

    This is not a limitation of the reflect package. Slice index expressions are addressable (e.g. &s[0] is valid for example), so slice elements obtained via reflection will be settable. Map index expressions are not addressable (e.g. &m["a"] is invalid), so values of keys obtained via reflection will not be settable. See related How to update map values in Go

    Only addressable values are settable, attempting to "set" a non-addressable value could only modify a copy (and not the original value), so it's not allowed in the first place. Quoting from Value.CanSet():

    CanSet reports whether the value of v can be changed. A Value can be changed only if it is addressable and was not obtained by the use of unexported struct fields.

    If you want to change the value assigned to a key in a map using reflection, use the Value.SetMapIndex() method:

    mv.SetMapIndex(reflect.ValueOf("a"), reflect.ValueOf("11"))
    fmt.Println(m)
    

    Output will be (try it on the Go Playground):

    map[b:2 c:3 a:11]
    

    Note: taking the address of a map index expression (and allowing to change a value using reflection) is not allowed because the internals of a map may change at any time (e.g. if new key-values are added to the map, the implementation may have to re-structure the way it stores the key-value pairs internally), so a possible pointer you would obtain by &m["a"] may not exist (or may point to another value) by the time you end up using it. To avoid such confusions and run-time panics, this is not allowed in the first place.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 LiBeAs的带隙等于0.997eV,计算阴离子的N和P
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 来真人,不要ai!matlab有关常微分方程的问题求解决,
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算