Using Go 1.16
Currently no plan to use Go 1.18
We have a scenario of using below struct:
type X struct {
M1 *int64
M2 *string
M3 *[]string
}
For below code:
package main
import (
"fmt"
"time"
)
type X struct {
M1 *int64
M2 *string
M3 *[]string
}
func main() {
slice := []string{"abc", "def"}
getIntPointer := func(i int64) *int64 {
return &i
}
getStringPointer := func(s string) *string {
return &s
}
getStringSlicePointer := func(slice []string) *[]string {
return &slice
}
value := X{
M1: getIntPointer(time.Now().Unix()),
M2: getStringPointer("00000000-0000-0000-0000-000000000000"),
M3: getStringSlicePointer(slice),
}
fmt.Println(value)
}
This function should expect input argument of any type (not just the above three types). Goal is to initialize value
.
Can a single function return a pointer of any type?
Type of the M1
, M2
and M3
fields are different, so without generics (Go 1.18) you can't have a function that have multiple return types, assignable to these different fields.
Before showing what's possible with older versions of Go (pre 1.18), let me tell you that I would not use them in production. They are inconvenient and slow (due to reflection). I would write helpers for different types and use those, or use a library that already has them, e.g. github.com/icza/gox
(package gox
) (disclosure: I'm the author).
And if Go 1.18 is allowed, I would use the generic solution shown at the end.
set()
using reflectionWhat you can do is write a helper that gets the address of a field and the value you want to set for it (more precisely a pointer to it), and using reflection this is doable.
This is how this helper could look like:
func set(p, v interface{}) {
rv := reflect.ValueOf(v)
rp := reflect.New(rv.Type())
rp.Elem().Set(rv)
reflect.ValueOf(p).Elem().Set(rp)
}
Using it:
slice := []string{"abc", "def"}
var value X
set(&value.M1, time.Now().Unix())
set(&value.M2, "00000000-0000-0000-0000-000000000000")
set(&value.M3, slice)
fmt.Println(*value.M1, *value.M2, *value.M3)
This will output (try it on the Go Playground):
1257894000 00000000-0000-0000-0000-000000000000 [abc def]
ptr()
using reflection and type assertionAnother, similarly inconvenient solution would be to write a single helper that returns a pointer to its argument using reflection:
func ptr(v interface{}) interface{} {
rv := reflect.ValueOf(v)
rp := reflect.New(rv.Type())
rp.Elem().Set(rv)
return rp.Interface()
}
The problem with this is that you have to use type assertion on the result:
value := X{
M1: ptr(time.Now().Unix()).(*int64),
M2: ptr("00000000-0000-0000-0000-000000000000").(*string),
M3: ptr(slice).(*[]string),
}
Try this one on the Go Playground.
If Go 1.18 will be allowed for you, a single helper is enough that uses no reflection:
func Ptr[T any](t T) *T {
return &t
}
And no type assertion is needed to use it:
value := X{
M1: Ptr(time.Now().Unix()),
M2: Ptr("00000000-0000-0000-0000-000000000000"),
M3: Ptr(slice),
}
Try this one on the Go Playground.
See related: How do I do a literal *int64 in Go?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With