How get pointer of struct's member from interface{} - pointers

I want to pass struct's pointer to function that expect interface{}. Then get (through reflection) the pointer to the struct's member and then modify it using this pointer. I've read a much of Q&A and tried much of variations, but still I can get it work.
Let's consider example below:
type Robot struct {
Id int
}
f := func(i interface {}) {
v := reflect.ValueOf(i).Elem().FieldByName("Id")
ptr := v.Addr().Pointer()
*ptr = 100
//^ it needs to me for functions expecting the pointer: Scan(&pointerToValue)
}
robot := &Robot{}
f(robot)
println(robot.Id) //I want to get here 100
I think the problem in poor understanding what actually do Addr() and Pointer() methods of reflect package..

Here's a working version of function f:
func f(i interface{}) {
v := reflect.ValueOf(i).Elem().FieldByName("Id")
ptr := v.Addr().Interface().(*int)
*ptr = 100
}
playground example
The conversion to integer pointer goes as follows:
v is a reflect.Value representing the int field.
v.Addr() is a relfect.Value representing a pointer to the int field.
v.Addr().Interface() is an interface{} containing the int pointer.
v.Addr().Interface().(*int) type asserts the interface{} to a *int
You can set the field directly without getting a pointer:
func f(i interface{}) {
v := reflect.ValueOf(i).Elem().FieldByName("Id")
v.SetInt(100)
}
playground example
If you are passing the value along to something expecting interface{} (like the db/sql Scan methods), then you can remove the type assertion:
func f(i interface{}) {
v := reflect.ValueOf(i).Elem().FieldByName("Id")
scan(v.Addr().Interface())
}
playground example

Related

Why do you have to use an asterisk for pointers but not struct pointers?

I think I am missing a part of technical background. But I don't get, why I have to use an * to access the value of a simple pointer, but not for accessing values of a struct.
For example with a simple value:
func main() {
i := 42
p := &i
*p = 21 // <<< I have to use an asterisk to access the value
// ...
}
And a example with a struct:
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9 // <<< I do not have to use an asterisk
// ...
}
(yes, the samples are from the official go lang tour here: https://go-tour-de.appspot.com/moretypes/4)
Just from my thoughts I would expect something like this
*p.X = 1e9
or (yeah, this would be somewhat strange)
p.*X = 1e9
So, why don't I have to use an asterisk to access struct pointer?
The official Golang tour where you found that example [here] explicitly says:
To access the field X of a struct when we have the struct pointer p we could write (*p).X. However, that notation is cumbersome, so the language permits us instead to write just p.X, without the explicit dereference.

Set an int pointer to an int value in Go

I'm very new to Go and am trying to set a *int to point to a number, say 12345.
package main
import (
"fmt"
"reflect"
)
func main() {
var guess *int
fmt.Println(reflect.TypeOf(guess))
*guess = 12345
fmt.Println(guess)
}
But it's giving me the following error:
Type: *int
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x483c7d]
goroutine 1 [running]:
main.main()
/home/aaron/projects/gopath/src/github.com/AaronNBrock/go-guess/main.go:16 +0x9d
exit status 2
I see that the error is with the *guess = 12345 since 12345, but I'm not sure what's causing it.
You have a pointer variable which after declaration will be nil.
If you want to set the pointed value, it must point to something. Attempting to dereference a nil pointer is a runtime panic, just what you experienced. You may use the builtin new() function to obtain a pointer to a zero-valued int, and then you can set the pointed value:
var guess *int
guess = new(int)
*guess = 12345
Your modified app:
var guess *int
fmt.Println(guess)
guess = new(int)
*guess = 12345
fmt.Println(guess, *guess)
Output (try it on the Go Playground):
<nil>
0x10414028 12345
Note that you can make this shorter using a short variable declaration like this:
guess := new(int)
*guess = 12345
Another option to make a pointer point to something "useful" is to assign the address of a variable to the pointer variable, like this:
value := 12345 // will be of type int
guess := &value
But this solution modifies the pointer value, not the pointed value. The result is the same though in this simple example.
You could also just assign the address of another variable, and then proceed to change the pointed value:
var value int
guess := &value
*guess = 12345
Also note that since guess points to value, changing the pointed value will change the value of the value variable too. Also if you change the value variable directly, the pointed value by guess also changes: they are one and the same:
var value int
guess := &value
value = 12345
fmt.Println(*guess) // This will also print 12345
Try this one on the Go Playground.
FWIW, if you do this often enough (like setting up data in unit tests) it's useful to have a shorthand, hence:
https://github.com/mwielbut/pointy
val := 42
pointerToVal := &val
// vs.
pointerToVal := pointy.Int(42)
Here's one possible utility function:
func getIntPointer(val int) *int {
return &val
}
Or as an inline anonymous function:
func(val int) *int { return &val }(val)
For example,
var foo *int = func(val int) *int { return &val }(10)
Run on The Go Playground
EDIT: It's probably better to make this a 2-liner:
val := new(int)
*val = 5
Assuming you really want an int pointer and not just an int, then you need a variable to store the int you point to. For example:
var guess *int
a := 12345
guess = &a
Starting from Go 1.18 you can make use of generics
func Pointer[K any](val K) *K {
return &val
}
A tricky way to get int pointer without create new variable.
someIntPtr := &[]int64{10}[0]
Like this, you don't have to use a one line func like func(val int) *int { return &val }(10) or create a variable of int.

reflect.New returns <nil> instead of initialized struct

I am using reflection for a library I'm building but there's something I don't understand about reflect.New.
type A struct {
A int
B string
}
func main() {
real := new(A)
reflected := reflect.New(reflect.TypeOf(real)).Elem().Interface()
fmt.Println(real)
fmt.Println(reflected)
}
Gives:
$ go run *go
&{0 }
<nil>
Isn't reflect.New supposed to return &{0 } too? (Runnable Version)
Ultimately, I wish to be able to iterate over the fields of the reflected struct (reflected.NumField() gives reflected.NumField undefined (type interface {} is interface with no methods)) and use SetInt, SetString and so on.
Thanks,
You used the builtin new() function when you created your real variable, which returns a pointer! Type of real is *A, not A! This is the source of the confusion.
reflect.New() returns a pointer to the (zeroed) value of the given type (wrapped in a reflect.Value). If you pass the type A, you get back a wrapped *A, A initialized / zeroed. If you pass the type *A, you get back a wrapped **A, *A initialized (zeroed), and the zero value for any pointer type is nil.
You basically ask reflect.New() to create a new value of a pointer type (*A), and –as mentioned– its zero value is nil.
You have to pass the type A (and not the type *A). It works like this (try it on the Go Playground):
real := new(A)
reflected := reflect.New(reflect.TypeOf(real).Elem()).Elem().Interface()
fmt.Println(real)
fmt.Println(reflected)
Or like this (Go Playground):
real := A{}
reflected := reflect.New(reflect.TypeOf(real)).Elem().Interface()
fmt.Println(real)
fmt.Println(reflected)

Pointer to interface with saving type

The shortest way to explain my problem is that code:
var i interface{} // I can't change it. In fact this is a function,
i = Item{10} // that receives interface{}, that contain object (not pointer to object!)
fmt.Printf("%T %v\n", i, i)
// fmt.Println(i.(NextValuer).NextVal()) // won't compile
i = &i
fmt.Printf("%T %v\n", i, i) // there i is pointer to interface{} (not to Item)
// fmt.Println(i.(NextValuer).NextVal()) // panics
// fmt.Println(i.(*NextValuer).NextVal()) // won't compile
But if I try to set pointer to Item to i, code works:
i = &Item{10}
fmt.Printf("%T %v\n", i, i)
fmt.Println(i.(NextValuer).NextVal())
But my function receives object, not pointer to it. And I can get type of it (first fmt.Printf). But when I try to make pointer to it, I receive pointer to interface{}, not to my Object (Item).
Can I make pointer to this object to call NextVal? Or may be other ways to do it
Never use a pointer to an interface. If you need a pointer to call a method with a pointer receiver, a pointer is what you must put into the interface{}.
If you have already have value in an interface{} where you want to call a method with a pointer receiver, you need to make an addressable copy of that value.
What you're trying to accomplish with i = &i is probably:
item := i.(Item)
i = &item
This creates an addressable copy of the original Item, and then puts a pointer to that copy into i. Note that this can never change the value of the original Item.
If you don't know the type that can be in the interface{}, you can make a copy of the value with "reflect":
func nextVal(i interface{}) {
// get the value in i
v := reflect.ValueOf(i)
// create a pointer to a new value of the same type as i
n := reflect.New(v.Type())
// set the new value with the value of i
n.Elem().Set(v)
// Get the new pointer as an interface, and call NextVal
fmt.Println("NextVal:", n.Interface().(NextValuer).NextVal())
// this could also be assigned another interface{}
i = n.Interface()
nv, ok := i.(NextValuer)
fmt.Printf("i is a NextValuer: %t\nNextVal: %d\n", ok, nv.NextVal())
}
http://play.golang.org/p/gbO9QGz2Tq

Rule for Go Pointers, References, Dereferencing:

I am new to GoLang, coming from the Delphi, C++ world - admittedly very excited about this language, which I think is destined to become "the next big thing".
I am trying to get a handle around how the Go parser and compiler handle pointers and references - can't seem to find any place where some clear rules are laid out.
In the below code sample for example, the return type *list.List and the local variable l are pointer types and require the pointer symbol * in their declarations, but they don't have to be dereferenced in use: l.PushBack(i). But in this same code the input parameter value *int64 is declared as a pointer and has to be dereferenced to be used properly: var i int64 = *value / 2
I assume that this is because list.List is a reference type, so the dereferencing is implicit when used, while int64 is a value type and must be handled just as any pointer to a value type, as in C++ for example: It must be dereferenced.
What is confusing to me is that even though *list.List has to be declared as a pointer type using *, when using the list instance, dereferencing is not required. This had me quite confused initially. Is that "just the way it is", or am I missing something?
Sample:
func GetFactors(value *int64) *list.List {
l := list.New()
l.PushBack(*value)
var i int64 = *value / 2
for ; i > 1; i-- {
if *value%i == 0 {
l.PushBack(i)
}
}
return l
}
All of the methods for a List have *List receivers: (http://golang.org/pkg/container/list/)
func (l *List) Back() *Element
func (l *List) Front() *Element
func (l *List) Init() *List
...
func (l *List) Remove(e *Element) interface{}
In your example l is of type *List, so there's no need to dereference them.
Suppose, instead, that you had something like this:
type A struct{}
func (a A) X() {
fmt.Println("X")
}
func (a *A) Y() {
fmt.Println("Y")
}
You are allowed to write:
a := A{}
a.X()
a.Y() // == (&a).Y()
Or you can do the following:
a := &A{}
a.X() // same like == (*a).X()
a.Y()
But it only works for method receivers. Go will not automatically convert function arguments. Given these functions:
func A(x *int) {
fmt.Println(*x)
}
func B(y int) {
fmt.Println(y)
}
This is invalid:
A(5)
You have to do this:
var x int
A(&x)
This is also invalid:
var y *int
B(y)
You have to do this:
B(*y)
Unlike C# or Java, when it comes to structs, Go does not make a distinction between reference and value types. A *List is a pointer, a List is not. Modifying a field on a List only modifies the local copy. Modifying a field on a *List modifies all "copies". (cause they aren't copies... they all point to the same thing in memory)
There are types which seem to hide the underlying pointer (like a slice contains a pointer to an array), but Go is always pass by value.

Resources