In C you can put function pointers into an array of void pointers and convert them back to function pointers of any type:
extern int (*fn1)(void);
extern void (*fn2)(int);
void foo(void)
{
void *array[2];
int i;
/* implicit cast from function pointer to void pointer */
array[0] = fn1;
array[1] = fn2;
for (i = 0; i < 2; i++)
{
int (*fp)(int, int, int);
/* implicit cast from void pointer to function pointer */
fp = array[i];
/* call function with a different signature */
fp(1, 2, 3);
}
}
I need to do the same in Go, using unsafe.Pointers. The questions are:
Can a Go function pointer be converted to an unsafe.Pointer?
Can an unsafe.Pointer be converted to a Go function pointer of a different (or the same) type as the original function pointer?
(The question is not why or whether I need to do that; in the given situation it is okay to call a function with the wrong set of parameters and to misinterpret the return value because the caller and the callees are able to deal with that.)
As LinearZoetrope's answer shows, you can do this. Beware that you can do bad things:
package main
import (
"fmt"
"unsafe"
)
func main() {
f1 := func(s string) {}
f2 := func(i int) int { return i + 1 }
pointers := []unsafe.Pointer{
unsafe.Pointer(&f1),
unsafe.Pointer(&f2),
}
f3 := (*func(int) bool)(pointers[1]) // note, not int
fmt.Println((*f3)(1))
}
playground
It appears to work:
package main
import (
"fmt"
"unsafe"
"math"
)
func main() {
fn := print
faked := *(*func(float64))(unsafe.Pointer(&fn))
faked(1.0)
// For comparison
num := math.Float64bits(1.0)
print(num)
}
func print(a uint64) {
fmt.Println(a)
}
Will print
4607182418800017408
4607182418800017408
Of course, you're probably well aware of the potential problems with trying this.
Related
This question already has answers here:
How can I access a struct field with generics (type T has no field or method)?
(1 answer)
Generic function to work on different structs with common members from external package?
(1 answer)
Closed 3 months ago.
There are two struct types, Foo and Bar, with an int data member val. I am trying to write a generic function that can handle both types. I tried the following and this did not work.
package main
import "fmt"
type Foo struct {
val int
}
type Bar struct {
val int
}
func Add[T any](slice []T) int {
var sum int
for _, elem := range slice {
sum += elem.val
}
return sum
}
func Test() {
f1 := Foo{val: 2}
f2 := Foo{val: 2}
fslice := []Foo{f1, f2}
fsum := Add(fslice)
fmt.Printf("fsum = %d\n", fsum)
b1 := Bar{val: 3}
b2 := Bar{val: 3}
bslice := []Bar{b1, b2}
bsum := Add(bslice)
fmt.Printf("bsum = %d\n", bsum)
}
func main() {
Test()
}
The compiler throws the following error.
$ go run generics1.go
# command-line-arguments
./generics1.go:16:15: elem.val undefined (type T has no field or method val)
Go playground link: https://go.dev/play/p/mdOMH3xuwu7
What could be a possible way to approach this?
Per golang 1.18 release note
The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in a future release.
You could define one GetVal() interface method to retrieve the val, and use this method as part of type constraint of generic.
Sample codes
type Foo struct {
val int
}
func (f Foo) GetVal() int {
return f.val
}
type Bar struct {
val int
}
func (b Bar) GetVal() int {
return b.val
}
type MyType interface {
Foo | Bar
GetVal() int
}
func Add[T MyType](slice []T) int {
var sum int
for _, elem := range slice {
sum += elem.GetVal()
}
return sum
}
https://go.dev/play/p/0eJZpqy7q8f
Is working example
package main
import "fmt"
func main() {
var newFunc func(int, int) int
newFunc = func(i int, j int) int {
return (i * j)
}
fmt.Println(newFunc(10, 20))
}
But if I taken out the function declaration part, out of main function (as shown below), it fails to compile.. Is mandatory to declare it inside main() function ?
package main
import "fmt"
var newFunc func(int, int) int
newFunc = func(i int, j int) int {
return (i * j)
}
func main() {
fmt.Println(newFunc(10, 20))
}
Compile Err details as follows:
.\functionanonymous1.go:6:1: syntax error: non-declaration statement outside function body
.\functionanonymous1.go:6:15: missing function body
.\functionanonymous1.go:6:33: method has multiple receivers
.\functionanonymous1.go:7:2: syntax error: unexpected return, expecting )
.\functionanonymous1.go:8:1: syntax error: non-declaration statement outside function body
In Go, while declaring variables outside functions, every declaration must begin with a keyword (ie. var). It might be kept in that way so that the parsing is less complicated.
So outside of functions, you can't assign a value to some pre-declared variable (i.e. v = 1 ) and also can't use short variable declarations (i.e. v := 1). You may have noticed that from the error logs, syntax error: non-declaration statement outside function body.
package main
var a int
a = 1 // illegal
b := 1 // illegal
var c = 1 // legal
func main() {}
Updated code:
package main
import "fmt"
var newFunc = func(i int, j int) int {
return (i * j)
}
func main() {
fmt.Println(newFunc(10, 20))
}
Go Playground
Simply, golang doesn't allow that. A variable that declares outside function must contain var.
So you can try:
package main
import "fmt"
var newFunc func(int, int) int = func(i int, j int) int {
return (i * j)
}
func main() {
fmt.Println(newFunc(10, 20))
}
I am trying to use cgo to use Go package in C code. Following is a piece of my code:
func LinearTransformToUInt8(frame []int64, winWidth int, winCenter int) []uint8 {
var transformed []uint8
// my cool code
return transformed
}
However, when calling from C, it says
panic: runtime error: cgo result has Go pointer
I believe the problem is the returned []uint8 is a Go type, which should be replaced by a C type. However, I don't know how to achieve it. Please help!
main.go
package main
import (
"C"
"unsafe"
)
import (
"reflect"
)
func main() {
}
//export phew
func phew() uintptr {
res := make([]uint8, 2)
for i := 0; i < 2; i++ {
res[i] = uint8(i + 1)
}
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&res))
return hdr.Data
}
main.c
#include <stdio.h>
#include <inttypes.h>
#include "libtemp.h"
int main(){
uintptr_t resPtr = phew();
uint8_t *res = (uint8_t*)resPtr;
for (int i = 0; i < 2; i++){
printf("%d\n", res[i]);
}
printf("Exiting gracefully\n");
}
You cannot pass a Go pointer which contains other Go Pointer, slice,string,channel,function, interface, map contain pointers.
So one cannot pass them around, rules to passing around pointers are documented here and go's representation of basic types is documented here.
But some Go contributors were saying, one shouldn't return a Go pointer to C code in the first place.
If I have a type which is not a struct how do I change its value with a pointer receiver?
For example, given the following code:
package main
import (
"fmt"
)
type MyInt int
func (i *MyInt) Change() {
newValue := MyInt(32)
i = &newValue
}
func main() {
myInt := MyInt(64)
fmt.Println(myInt)
myInt.Change()
fmt.Println(myInt)
}
It outputs:
64
64
Why does it not output the following:
64
32
?
You're changing the value of the pointer i, not the value at which the pointer is pointing.
You will see your expected output by using the * operator:
*i = newValue
https://play.golang.org/p/mKsKC0lsj9
for your function define:
func (i *MyInt) Change() {
newValue := MyInt(32)
i = &newValue
}
when you call this function:
myInt := MyInt(64)
myInt.Change()
the value of myInt will pass to i, so after call func (i *MyInt) Change(), you only modify the i, not myInt.
I am trying to create function pointer to a function that has a method receiver. However, I can't figure out how to get it to work (if it is possible)?
Essentially, I have the following:
type Foo struct {...}
func (T Foo) Bar bool {
...
}
type BarFunc (Foo) func() bool // Does not work.
The last line of the code gives the error
syntax error: unexpected func, expecting semicolon or newline
If you want to create a function pointer to a method, you have two ways. The first is essentially turning a method with one argument into a function with two:
type Summable int
func (s Summable) Add(n int) int {
return s+n
}
var f func(s Summable, n int) int = (Summable).Add
// ...
fmt.Println(f(1, 2))
The second way will "bind" the value of s (at the time of evaluation) to the Summable receiver method Add, and then assign it to the variable f:
s := Summable(1)
var f func(n int) int = s.Add
fmt.Println(f(2))
Playground: http://play.golang.org/p/ctovxsFV2z.
Any changes to s after f is assigned will have no affect on the result: https://play.golang.org/p/UhPdYW5wUOP
And for an example more familiar to those of us used to a typedef in C for function pointers:
package main
import "fmt"
type DyadicMath func (int, int) int // your function pointer type
func doAdd(one int, two int) (ret int) {
ret = one + two;
return
}
func Work(input []int, addthis int, workfunc DyadicMath) {
for _, val := range input {
fmt.Println("--> ",workfunc(val, addthis))
}
}
func main() {
stuff := []int{ 1,2,3,4,5 }
Work(stuff,10,doAdd)
doMult := func (one int, two int) (ret int) {
ret = one * two;
return
}
Work(stuff,10,doMult)
}
https://play.golang.org/p/G5xzJXLexc
I am very likely off-target (just started on Golang) but what if you create a pointer then examine type:
pfun := Bar
fmt.Println("type of pfun is:", reflect.TypeOf(pfun))
then it seems that you can declare the type of pointer correctly:
https://play.golang.org/p/SV8W0J9JDuQ