Why is it possible to set a value in a slice using reflection?

huangapple go评论85阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2014年6月27日 05:56:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/24440902.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定