reflect: add PtrTo, add Value.Addr (old Addr is now UnsafeAddr)

This change makes it possible to take the address of a
struct field or slice element in order to call a method that
requires a pointer receiver.

Existing code that uses the Value.Addr method will have
to change (as gob does in this CL) to call UnsafeAddr instead.

R=r, rog
CC=golang-dev
https://golang.org/cl/4239052
This commit is contained in:
Russ Cox 2011-03-03 13:20:17 -05:00
parent 44fd7573aa
commit e46acb091f
6 changed files with 285 additions and 52 deletions

View file

@ -1093,6 +1093,18 @@ func TestMethod(t *testing.T) {
t.Errorf("Value Method returned %d; want 250", i)
}
// Curried method of pointer.
i = NewValue(&p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
if i != 250 {
t.Errorf("Value Method returned %d; want 250", i)
}
// Curried method of pointer to value.
i = NewValue(p).Addr().Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
if i != 250 {
t.Errorf("Value Method returned %d; want 250", i)
}
// Curried method of interface value.
// Have to wrap interface value in a struct to get at it.
// Passing it to NewValue directly would
@ -1390,3 +1402,66 @@ func TestEmbeddedMethods(t *testing.T) {
t.Errorf("f(o) = %d, want 2", v)
}
}
func TestPtrTo(t *testing.T) {
var i int
typ := Typeof(i)
for i = 0; i < 100; i++ {
typ = PtrTo(typ)
}
for i = 0; i < 100; i++ {
typ = typ.(*PtrType).Elem()
}
if typ != Typeof(i) {
t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, Typeof(i))
}
}
func TestAddr(t *testing.T) {
var p struct {
X, Y int
}
v := NewValue(&p)
v = v.(*PtrValue).Elem()
v = v.Addr()
v = v.(*PtrValue).Elem()
v = v.(*StructValue).Field(0)
v.(*IntValue).Set(2)
if p.X != 2 {
t.Errorf("Addr.Elem.Set failed to set value")
}
// Again but take address of the NewValue value.
// Exercises generation of PtrTypes not present in the binary.
v = NewValue(&p)
v = v.Addr()
v = v.(*PtrValue).Elem()
v = v.(*PtrValue).Elem()
v = v.Addr()
v = v.(*PtrValue).Elem()
v = v.(*StructValue).Field(0)
v.(*IntValue).Set(3)
if p.X != 3 {
t.Errorf("Addr.Elem.Set failed to set value")
}
// Starting without pointer we should get changed value
// in interface.
v = NewValue(p)
v0 := v
v = v.Addr()
v = v.(*PtrValue).Elem()
v = v.(*StructValue).Field(0)
v.(*IntValue).Set(4)
if p.X != 3 { // should be unchanged from last time
t.Errorf("somehow value Set changed original p")
}
p = v0.Interface().(struct {
X, Y int
})
if p.X != 4 {
t.Errorf("Addr.Elem.Set valued to set value in top value")
}
}