英文:
Why is it possible to set a value in a slice using reflection?
问题
根据反射定律,不能像下面这样设置元素的值,需要使用其地址。
以下代码无法工作:
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // 错误:会引发 panic。
以下代码可以工作:
var x float64 = 3.4
p := reflect.ValueOf(&x) // 注意:取 x 的地址。
p.Elem().SetFloat(7.1)
那么为什么在使用切片时以下代码可以工作呢?
floats := []float64{3}
v := reflect.ValueOf(floats)
e := v.Index(0)
e.SetFloat(6)
fmt.Println(floats) // 输出 [6]
http://play.golang.org/p/BWLuq-3m85
显然,v.Index(0)
是从切片 floats
中取得值而不是地址,所以它不应该像第一个例子那样可设置。
英文:
According to The Laws of Reflection it is not possible to set the value of an element as follows, you need to use its address.
This will not work:
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.
This will work:
var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
p.Elem().SetFloat(7.1)
So why will the following work when using slices?
floats := []float64{3}
v := reflect.ValueOf(floats)
e := v.Index(0)
e.SetFloat(6)
fmt.Println(floats) // prints [6]
http://play.golang.org/p/BWLuq-3m85
Surely v.Index(0)
is taking the value instead of address from slice floats
, thus meaning it shouldn't be settable like the first example.
答案1
得分: 7
在你的第一个示例中,你传递了实际的 x
。这将复制 x
并将其传递给 reflect.ValueOf
。当你尝试执行 v.SetFloat
时,由于它只得到了一个副本,它无法改变原始的 x
变量。
在你的第二个示例中,你传递了 x
的地址,因此你可以通过解引用来访问原始变量。
在第三个示例中,你将 floats
传递给了 reflect.ValueOf
,它是一个切片。"切片保存对底层数组的引用"(http://golang.org/doc/effective_go.html#slices)。这意味着通过切片,你实际上拥有对底层对象的引用。你无法改变切片本身(如 append
等),但你可以改变切片所引用的内容。
英文:
In your first example, you pass the actual x
. This will copy x
and give it to reflect.ValueOf
. When you try to do v.SetFloat
, as it get only a copy, it has no way to change the original x
variable.
In your second example, you pass the address of x
, so you can access the original variable by dereferencing it.
In the third example, you pass floats
to reflect.ValueOf
, which is a slice. "Slice hold references to the underlying array" (http://golang.org/doc/effective_go.html#slices). Which mean that through the slice, you actually have a reference to the underlying object. You won't be able to change the slice itself (append
& co) but you can change what the slice refers to.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论