generic function to get size of any structure in Go - go

I am writing a generic function to get the size of any type of structure, similar to sizeof function in C.
I am trying to do this using interfaces and reflection but I'm not able to get the correct result. Code is below:
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
type myType struct {
a int
b int64
c float32
d float64
e float64
}
info := myType{1, 2, 3.0, 4.0, 5.0}
getSize(info)
}
func getSize(T interface{}) {
v := reflect.ValueOf(T)
const size = unsafe.Sizeof(v)
fmt.Println(size)
}
This code returns wrong result as 12. I am very new to Go, kindly help me on this.

You're getting the size of the reflect.Value struct, not of the object contained in the interface T. Fortunately, reflect.Type has a Size() method:
size := reflect.TypeOf(T).Size()
This gives me 40, which makes sense because of padding.

Go 1.18
With Go 1.18 you can use a generic function with unsafe.Sizeof:
func getSize[T any]() uintptr {
var v T
return unsafe.Sizeof(v)
}
Note that this will be more performant than using reflect, but it will introduce unsafe in your code base — some static analysis tools may give warnings about that.
However if your goal is to improve code reuse or get sizes at run time (read on for the solution to that), this won't help much because you still need to call the function with proper instantiation:
type myType struct {
a int
b int64
c float32
d float64
e float64
}
func main() {
fmt.Println(getSize[myType]())
}
You might get the most out of this when used as part of some other generic code, e.g. a generic type or function where you pass a type param into getSize. Although if you have the argument v this is equivalent to calling unsafe.Sizeof(v) directly. Using a function could be still useful to hide usage of unsafe. A trivial example:
func printSize[T any](v T) {
// (doing something with v)
// instantiate with T and call
s := getSize[T]()
// s := unsafe.Sizeof(v)
fmt.Println(s)
}
Otherwise you can pass an actual argument to getSize. Then type inference will make it unnecessary to specify the type param. This code perhaps is more flexible and allows you to pass arbitrary arguments at runtime, while keeping the benefits of avoiding reflection:
func getSize[T any](v T) uintptr {
return unsafe.Sizeof(v)
}
func main() {
type myType struct {
a int
b int64
c float32
d float64
e float64
}
info := myType{1, 2, 3.0, 4.0, 5.0}
// inferred type params
fmt.Println(getSize(info)) // 40
fmt.Println(getSize(5.0)) // 8
fmt.Println(getSize([]string{})) // 24
fmt.Println(getSize(struct {
id uint64
s *string
}{})) // 16
}
Playground: https://go.dev/play/p/kfhqYHUwB2S

Related

How to write a pop() function

a := []int{1,2,3}
x, a := a[len(a)-1], a[:len(a)-1]
fmt.Println(a,x)
How to create a pop() function that will do the same for any type of an array?
Here is what I came up with so far:
func pop(a []*interface{}) interface{}{
x := a[len(a)-1]
a = a[:len(a)-1]
return x
}
func main(){
a := []int{1,2,3}
x = pop(a)
fmt.Println(a,x) // -> [1,2] 3
}
But I get cannot use a (type []int) as type []interface {}or other error messages if I try to tweak the code by trial and error.
package main
import (
"fmt"
"reflect"
)
func pop(a interface{}) interface{} {
v := reflect.ValueOf(a).Elem()
x := v.Index(v.Len() - 1)
v.SetLen(v.Len() - 1)
return x
}
func main() {
a := []int{1, 2, 3}
x := pop(&a)
fmt.Println(a, x) // -> [1,2] 3
}
Though this can be implemented, I still think that x, a = a[len(a)-1], a[:len(a)-1] should be better than a pop function.
The go type system doesn't allow you to cast from []type1 -> []type2. Even if it did interfaces are a struct containing a type id and pointer to the object, where normally you would just have the object. Because of this you need to take a interface{} and use reflect to do the slicing.
func pop(slice interface{}) (interface{}, interface{}) {
v := reflect.ValueOf(slice)
return v.Slice(0,v.Len()-1).Interface(), v.Index(v.Len()-1).Interface()
}
Go Playground
Note that this loses compile time type safety, because it must use an interface. Additionally, due to using interfaces the poped value may be allocated, creating extra GC pressure.
Common Go style typically recommends not writing a function like this, and just inlining the small amount of code manually.
After all that really good anwers using reflection I also want to add one answer which offers a more idiomatic Go solution. Like Rob Pike said in his great talk about Go Proverbs
interface{} says nothing
Reflection is never clear
So there should be also one answer showing the idiomatic Go way. This solution does not work for slices of standard types. But there the answer of cshu shows the best solution: x, a = a[len(a)-1], a[:len(a)-1]
For own defined types we have to define a Poper interface and the Pop function takes that as input and returns an empty interface.
type Poper interface {
Pop() interface{}
}
type MyType struct {
a []int
}
func (mt *MyType) Pop() interface{} {
x := mt.a[len(mt.a)-1]
mt.a = mt.a[:len(mt.a)-1]
return x
}
func Pop(p Poper) interface{} {
return p.Pop()
}
func main() {
a := &MyType{[]int{1, 2, 3}}
fmt.Println(Pop(a), a)
}
https://play.golang.org/p/UbDkoVYSMA
At all it is not a good idea to return an empty interface, because all following code has to support the interface{}.
The following code example does not work:
func main() {
a := &MyType{[]int{1, 2, 3}}
fmt.Println(Pop(a), a)
var b int
b = Pop(a)
}
https://play.golang.org/p/wg9__O44A8
The error says everything about that problem: cannot use Pop(a) (type interface {}) as type int in assignment: need type assertion
So the Pop() function does work by returning interface{} but the rest of the code using the result of that function needs to make a type assertion. So if you can avoid it you should search for another solution using types.

Golang: convert struct to embedded at offset 0 struct

I have some different structs like Big with Small embedded at offset 0.
How can I access Small's structure fields from code, that doesn't know anything about Big type, but it is known that Small is at offset 0?
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
var v interface{} = Big{}
// here i only know about 'Small' struct and i know that it is at the begining of variable
v.(Small).val // compile error
It seems that compiler is theoretically able to operate such expression, because it knows that Big type has Small type embedded at offset 0. Is there any way to do such things (maybe with unsafe.Pointer)?
While answer with reflection is working but it has performance penalties and is not idiomatic to Go.
I believe you should use interface. Like this
https://play.golang.org/p/OG1MPHjDlQ
package main
import (
"fmt"
)
type MySmall interface {
SmallVal() int
}
type Small struct {
val int
}
func (v Small) SmallVal() int {
return v.val
}
type Big struct {
Small
bigval int
}
func main() {
var v interface{} = Big{Small{val: 3}, 4}
fmt.Printf("Small val: %v", v.(MySmall).SmallVal())
}
Output:
Small val: 3
Avoid using unsafe whenever possible. The above task can be done using reflection (reflect package):
var v interface{} = Big{Small{1}, 2}
rf := reflect.ValueOf(v)
s := rf.FieldByName("Small").Interface()
fmt.Printf("%#v\n", s)
fmt.Printf("%#v\n", s.(Small).val)
Output (try it on the Go Playground):
main.Small{val:1}
1
Notes:
This works for any field, not just the first one (at "offset 0"). This also works for named fields too, not just for embedded fields. This doesn't work for unexported fields though.
type Small struct {
val int
}
type Big struct {
Small
bigval int
}
func main() {
var v = Big{Small{10},200}
print(v.val)
}

Functions type converting

How can I convert func add (a, b int) int to func(...interface{}) interace{} type ?
Any ideas about implementing generic functions using the reflect package ?
As JimB said, you can't cast in Go and you cannot convert functions just like that but by using closures, you can rapidly wrap your function:
func add(a, b int) int {
return a + b;
}
wrap := func(args ...interface{}) interface{} {
return interface{} (add(args[0].(int), args[1].(int)))
}
Note that wrap will panic if you give it arguments that are not of type int. If you want to avoid that you can slightly modify wrap:
wrap := func(args ...interface{}) (interface{}, error) {
a, k := args[0].(int)
b, l := args[1].(int)
if !k || !l {
return nil, errors.New("Arguments must be of type int")
}
return add(a,b), nil
}
If you'd like to do different things with wrap, depending on it's arguments types you can do so by using a type switch:
func addInts(a, b int) int {
return a + b;
}
func addFloat64s(a, b float64) float64 {
return a + b;
}
wrap := func(args ...interface{}) interface{} {
switch args[0].(type) {
case int: return interface{}(addInts(args[0].(int), args[1].(int)))
case float64: return interface{}(addFloat64s(args[0].(float64), args[1].(float64)))
}
}
Note that this last version of wrap makes the assumption that all given parameters will have the same type and at least 2 arguments are given.
There is no "casting" is go (well, using the "unsafe" package kind of is like casting).
You cannot convert function types like this, since they have different layouts in memory. Generic-like functions can be made through the reflect package, though with significant overhead. See http://golang.org/pkg/reflect/#example_MakeFunc for an example.
For most use cases of generic functions, you're probably better off accepting an interface, and using type assertions or switches (http://golang.org/ref/spec#Type_switches), rather than the reflection library.

golang: can i share C.int between packages

in the main package i have:
var foo C.int
foo = 3
t := fastergo.Ctuner_new()
fastergo.Ctuner_register_parameter(t, &foo, 0, 100, 1)
in the fastergo package i have:
func Ctuner_register_parameter(tuner unsafe.Pointer, parameter *C.int, from C.int, to C.int, step C.int) C.int {
...
}
if i try to run it, i get:
demo.go:14[/tmp/go-build742221968/command-line-arguments/_obj/demo.cgo1.go:21]: cannot use &foo (type *_Ctype_int) as type *fastergo._Ctype_int in function argument
i am not really sure what go is trying to tell me here, but somehow i think it wants to tell me, that all C.int are not equal? why is this the case? how can i solve this / work around?
Since _Ctype_int doesn't begin with a Unicode upper case letter, the type is local to the package. Use Go types, except in the C wrapper package where you convert them to C types. The wrapper package should hide all the implementation details.
You don't provide sufficient information for us to create sample code which compiles and runs. Here's a rough outline of what I expected to see:
package main
import "tuner"
func main() {
var foo int
foo = 3
t := tuner.New()
t.RegisterParameter(&foo, 0, 100, 1)
}
.
package tuner
import (
"unsafe"
)
/*
#include "ctuner.h"
*/
import "C"
type Tuner struct {
ctuner uintptr
}
func New() *Tuner {
var t Tuner
t.ctuner = uintptr(unsafe.Pointer(C.ctuner_new()))
return &t
}
func (t *Tuner) RegisterParameter(parameter *int, from, to, step int) error {
var rv C.int
rv = C.ctuner_register_parameter(
(*C.ctuner)(unsafe.Pointer(t.ctuner)),
(*C.int)(unsafe.Pointer(parameter)),
C.int(from),
C.int(to),
C.int(step),
)
if rv != 0 {
// handle error
}
return nil
}
As explained by peterSO, you can't pass C.int between packages. However, you can pass pointers between packages by converting the pointer type. To do this, you would define a named type in the target package, import that type into the calling package and covert via unsafe.Pointer. There isn't any point in doing this with a single int.
However, it is helpful if you keep code to convert complex types in a package; for example an array of strings (or any sort of nested array).
The example below is for exporting a go function to be called in C, but this works in reverse, ie. if you want to call a C functions which a returns nested array.
package convert
import "C"
type PP_char **C.char
func From_c_to_go(arr_str PP_char, length int) []string {
// Some operation on the Ctype
var slice []string
for _, s := range unsafe.Slice(arr_str, length) {
if s == nil {
break
}
x := C.GoString(s)
slice = append(slice, x)
}
return slice
}
package main
import "C"
import "convert"
//export myFunc
func myFunc(arr_str **C.char, length int){
retyped_arr_str := convert.PP_char(unsafe.Pointer(arr_str))
slice := convert.From_c_to_go(retyped_arr_str, length)
// Do something with slice
}
You could instead decide to pass instance of unsafe.Pointer as an argument to the go function in the target package and perform the type conversion in that function.

Using function names as parameters

In Go, you can pass functions as parameters like callFunction(fn func). For example:
package main
import "fmt"
func example() {
fmt.Println("hello from example")
}
func callFunction(fn func) {
fn()
}
func main() {
callFunction(example)
}
But is it possible to call a function when it's a member of a struct? The following code would fail, but gives you an example of what I'm talking about:
package main
import "fmt"
type Example struct {
x int
y int
}
var example Example
func (e Example) StructFunction() {
fmt.Println("hello from example")
}
func callFunction(fn func) {
fn()
}
func main() {
callFunction(example.StructFunction)
}
(I know what I'm trying to do in that example is a little odd. The exact problem I have doesn't scale down to a simple example very well, but that's the essence of my problem. However I'm also intrigued about this from an academic perspective)
Methods (which are not "members of a struct" but methods of any named type, not only structs) are first class values. Go 1.0.3 didn't yet implemented method values but the tip version (as in the comming Go 1.1) has support method values. Quoting the full section here:
Method values
If the expression x has static type T and M is in the method set of type T, x.M is called a method value. The method value x.M is a function value that is callable with the same arguments as a method call of x.M. The expression x is evaluated and saved during the evaluation of the method value; the saved copy is then used as the receiver in any calls, which may be executed later.
The type T may be an interface or non-interface type.
As in the discussion of method expressions above, consider a struct type T with two methods, Mv, whose receiver is of type T, and Mp, whose receiver is of type *T.
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
var pt *T
func makeT() T
The expression
t.Mv
yields a function value of type
func(int) int
These two invocations are equivalent:
t.Mv(7)
f := t.Mv; f(7)
Similarly, the expression
pt.Mp
yields a function value of type
func(float32) float32
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mv is equivalent to (&t).Mv.
f := t.Mv; f(7) // like t.Mv(7)
f := pt.Mp; f(7) // like pt.Mp(7)
f := pt.Mv; f(7) // like (*pt).Mv(7)
f := t.Mp; f(7) // like (&t).Mp(7)
f := makeT().Mp // invalid: result of makeT() is not addressable
Although the examples above use non-interface types, it is also legal to create a method value from a value of interface type.
var i interface { M(int) } = myVal
f := i.M; f(7) // like i.M(7)
Go 1.0 does not support the use of bound methods as function values. It will be supported in Go 1.1, but until then you can get similar behaviour through a closure. For example:
func main() {
callFunction(func() { example.StructFunction() })
}
It isn't quite as convenient, since you end up duplicating the function prototype but should do the trick.
I fixed your compile errors.
package main
import "fmt"
type Example struct {
x, y float64
}
var example Example
func (e Example) StructFunction() {
fmt.Println("hello from example")
}
func callFunction(fn func()) {
fn()
}
func main() {
callFunction(example.StructFunction)
}
Output:
hello from example
To add to #zzzz great answer (and the one given at https://golang.org/ref/spec#Method_values) here is an example that creates a method value from a value of an interface type.
package main
import "fmt"
type T struct{}
func (T) M(i int) { fmt.Println(i) }
func main() {
myVal := T{}
var i interface{ M(int) } = myVal
f := i.M
f(7) // like i.M(7)
}

Resources