I know that functions can be passed as parameters. But I would like to use a function taking a type implementing an interface as input to a function. Is this still possible?
I have tried the following and it gives cannot use myfn1 (type func(int)) as type fn in argument to test as error.
package main
import "fmt"
type intf interface{}
type fn func(i intf)
func myfn1(i int) {
fmt.Printf("\ni is %v", i)
}
func myfn2(i int) {
fmt.Printf("\ni is %v", i)
}
func test(f fn, val int) {
f(val)
}
func main() {
test(fn(myfn1), 123)
test(myfn2, 321)
}
You can try it at: https://play.golang.org/p/Al7USxzmYST
Changing type fn func(i intf) to type fn func(i int) of course solves the issue. But I don't understand whether it can be made to work with the interface.
You can pass any type of function as an argument. However, when you pass a function as an argument, the function signature has to match. So you cannot pass a function taking an interface in place of a function that takes an int.
Passing an interface value to a function is different than passing an int. When you call a function with an int value, it simply passes that value. But when you pass a int value to a function getting interface{}, it has to create an interface value containing the type of the value and the value itself, and pass that.
Related
Below code in python:
def print_all(x):
print(x)
return print_all
allows to call print_all(1)(2) or print_all(1)(2)(3)(4)
Edit
Another example in python:
def print_sums(x):
print(x)
def next_sum(y):
return print_sums(x+y)
return next_sum
print_sums(1)(3)(5)
which maps to syntax:
package main
import "fmt"
type printsumfunctype func(x int) printsumfunctype
func printSums(x int) printsumfunctype {
fmt.Println(x)
var nextSum func(y int) printsumfunctype
nextSum = func(y int) printsumfunctype {
return printSums(x + y)
}
return nextSum
}
func main() {
printSums(1)(2)(3)
}
In GoLang, function is first class
1) What is the syntax to self reference a function in GoLang?
2) What is the preferred naming convention to define types like printsumfunctype?
You define a recursive function type:
type Printer func(interface{}) Printer
func printAll(x interface{}) Printer {
fmt.Println(x)
return printAll
}
func main() {
printAll(1)("Hello")
}
For the new code, you would write
type Sink func(int) Sink // not really different, is it?
func printSums(x int) Sink {
fmt.Println(x)
return func(y int) Sink {
return printSums(x + y)
}
}
A useful naming convention is to just name the types after their functions. In both of these cases, Printer (basically function verb + "er") works. Or, the more generic term Sink also fits, as it's a black hole that you can just keep dumping items into. I don't think there's any rule for it; these types aren't very common. Just pick a descriptive name.
I am currently in UCI Go Lang Course and Came across this function which the Syntax I did not understand. The function is directly from the example code, but has a syntax error I do not understand line 2 bracket. Also I come from JS, and C and Why in go are some functions declared without outer brackets?
func MakeDistOrigin(o_x, o_y float64)
func (float64, float64) float64 {
fn := func (x, y float64) float64 {
return math.Sqrt(math.Pow(x - o_x, 2) +
math.Pow(y - o_y, 2))
}
return fn
}
I expected this function to have outer brackets for each function and to return a function that then takes in another variable. Thanks!
If you got a syntax error, probably you have a newline after func MakeDistOrigin(o_x, o_y float64). Move the func (float64, float64) float64 { to the same line as the MakeDistOrigin declaration, and it should be good.
The second line in the code you pasted is not a function declaration. It is the return type of MakeDistOrigin. Look at it this way:
func MakeDistOrigin(o_x, o_y float64) T {
}
In the above declaration, T is the following type:
func (float64, float64) float64
So in fact you can simplify this declaration by:
type T func (float64, float64) float64
func MakeDistOrigin(o_x, o_y float64) T {
}
So MakeDistOrigin is a function that returns a function of type T, which is a function that gets two float64 values and returns a float64 value.
Inside MakeDistOrigin, a variable fn is declared. This variable is of type T as well, that is a function that takes two float64s and returns one.
The variable fn is initialized with the function definition given next to it, which is, again, a function of type T.
Is it possible to do something like this in Golang?
package main
import "fmt"
type myFunType func(x int) int
var myFun myFunType = myFunType { return x } // (1)
func doSomething(f myFunType) {
fmt.Println(f(10))
}
func main() {
doSomething(myFun)
}
In other words, is it possible to declare a function type variable using a function type alias, without repeating the signature?
Or, alternatively, is there a way not to always retype the whole function-signature, whenever creating a variable of a function-type?
The above code sample, which I would expect to be equivalent to the one below (replace line (1) with line (2)), results in the compilation error syntax error: unexpected return, expecting expression.
package main
import "fmt"
type myFunType func(x int) int
var myFun myFunType = func(x int) int { return 2 * x } // (2)
func doSomething(f myFunType) {
fmt.Println(f(10))
}
func main() {
doSomething(myFun)
}
From Spec: Function literals:
FunctionLit = "func" Signature FunctionBody .
A function literal must contain the func keyword and the Signature. Using a function type is not allowed by the syntax.
Same goes for Function declarations:
FunctionDecl = "func" FunctionName Signature [ FunctionBody ] .
Using a function type (instead of the signature) is not allowed.
So no, what you want is not possible. And the reason for it is because the signature (the function type) does not include the parameter names (just their order and types), but when you are actually "creating" a function value, you need a way to refer to them, and having just the function type you don't have names for the parameters.
See related questions for more details:
Getting method parameter names in Golang
Is unnamed arguments a thing in Go?
No, but in golang you can define methods with a name and use them.
As an example. Sometimes at the top of a file or even in a whole package there is a common way of defining errors like this:
ErrFileNotFound := func(file string) error { return errors.New(fmt.Sprintf("file not found %v", file)) }
And this function can then be used multiple times in the file like
file, err := os.Open(filenameRequestedToOpen) // For read access.
if err != nil {
log.Fatal(ErrFileNotFound(filenameRequestedToOpen))
}
or see https://play.golang.org/p/CvBGGc3YeX4
var myFun myFunType = func(x int) int { return 2 * x } // (2)
this is ok, myFun must contains func keyword,means it's a func type of myFunType, and parameters and return type must same with myFunType declared.
Given this short program:
package main
import "fmt"
type Foo struct {
doer func()
}
func (f Foo) SetDoer(doer func()) {
f.doer = doer
}
func main() {
foo := Foo{func() { fmt.Println("original") }}
foo.doer()
foo.SetDoer(func() { fmt.Println("replacement") })
foo.doer()
}
The output is:
original
original
I had expected it to be:
original
replacement
Why isn't it? Note that the output is as expected if I set foo.doer directly in main(). Just not if I use the SetDoer method.
In Go, the item on the left of the function name is the receiving type. This is the type from which a function can be called. However, receiver can be both pointers or value types. In this case, it is a value. The receiver is purely for the purpose of organization, under the covers, it is passed to the function like any other argument. You're passing by value so a copy of foo is passed into SetDoer, the value is modified, then the setter returns, the value goes out of scope and in the calling scope you're working with the original.
Try this;
// make the receiver a pointer
func (f *Foo) SetDoer(doer func()) {
f.doer = doer
}
// instantiate as pointer
foo := &Foo{func() { fmt.Println("original") }}
foo.SetDoer(func() { fmt.Println("replacement") })
// now the version of doer on foo has been updated.
playground example; https://play.golang.org/p/ZQlvKiluu3
Simple version
How can you create a variable of a certain type based upon the value of a string?
type ta struct { a int }
type tb struct { b float }
type tc struct { c string }
t := "tb"
v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
v.(tb).b = 8.3
The true example
In my, surprisingly enough, working example below, I am dynamically creating variables based on a string. This is done by registering each struct type in a map with the string being the key and a nil-pointer of the type being the value.
Each type implements an interface with the method New() which returns a new variable of that specific type.
The example below is very close to what I wish to do, where each action has a set of JSON encoded data which will populate the corresponding struct. The way I've structured it is also because I wish to be able to create new stand alone actions that I register to the map.
I am not sure if am abusing the language now.
May anyone give me any pointers if I am completely out of my mind? Is there an obviously easier way?
package main
import (
"fmt"
"encoding/json"
)
// All I require of an action is that it may be executed
type ActionHandler interface {
Exec()
New() ActionHandler
}
// My list of actions
var mActions = make(map[string]ActionHandler)
// Action Exit (leaving the program)
type aExit struct {}
func (s *aExit) Exec() { fmt.Println("Good bye") }
func (s *aExit) New() ActionHandler { return new(aExit) }
func init() {
var a *aExit
mActions[`exit`] = a
}
// Action Say (say a message to someone)
type aSay struct {
To string
Msg string
}
func (s *aSay) Exec() { fmt.Println(`You say, "` + s.Msg + `" to ` + s.To) }
func (s *aSay) New() ActionHandler { return new(aSay) }
func init() {
var a *aSay
mActions[`say`] = a
}
func inHandler(action string, data []byte) {
a := mActions[action].New()
json.Unmarshal(data, &a)
a.Exec()
}
func main(){
inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
inHandler(`exit`, []byte(`{}`))
}
You can use reflection to get the zero value of, or to allocate a new value (like new) of a type using reflection, if you can get the Type value at runtime. However, I don't think there is a way to get the Type from a string. You would need to have a value of that type to get the type itself.
I adopted your idea, of using a map. I map the string to the type itself, which you can get using reflect.TypeOf, which gets the type out of an interface value. Then I used reflect.Zero to get the zero value of that type (a convenient value that exists for every type). Then I got the value out as an interface.
package main
import "reflect"
type ta struct { a int }
type tb struct { b float64 }
type tc struct { c string }
var mActions map[string]reflect.Type = make(map[string]reflect.Type)
func init() {
var a ta
mActions[`ta`] = reflect.TypeOf(a)
var b tb
mActions[`tb`] = reflect.TypeOf(b)
var c ta
mActions[`tc`] = reflect.TypeOf(c)
}
func MagicVarFunc(action string) interface{} {
return reflect.Zero(mActions[action]).Interface()
}
func main() {
t := "tb"
v := MagicVarFunc(t) // Returns a new allocated var of type interface{}
x := v.(tb)
x.b = 8.3
}
jorelli's answer is very good. I'm just going to show a few options. Your "true example" looks essentially like command dispatch, with command parameters specified with JSON. To start with simple code that does this,
package main
import (
"encoding/json"
"fmt"
)
func inHandler(action string, data []byte) {
arg := make(map[string]interface{})
json.Unmarshal(data, &arg)
switch action {
case "say":
fmt.Printf("You say, %q to %s\n", arg["msg"], arg["to"])
case "exit":
fmt.Println("Good bye")
}
}
func main() {
inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
inHandler(`exit`, []byte(`{}`))
}
Your register new commands by adding cases to the switch statement. Yeah, didn't think you'd like that. So, adding your map and init() idea,
package main
import (
"encoding/json"
"fmt"
)
type jmap map[string]interface{}
var mActions = map[string]func(jmap){}
func init() {
mActions["say"] = func(arg jmap) {
fmt.Printf("You say, %q to %s\n", arg["msg"], arg["to"])
}
}
func init() {
mActions["exit"] = func(jmap) { fmt.Println("Good bye") }
}
func inHandler(action string, data []byte) {
args := make(jmap)
json.Unmarshal(data, &args)
mActions[action](args)
}
func main() {
inHandler(`say`, []byte(`{"to":"Sonia","msg":"Please help me!"}`))
inHandler(`exit`, []byte(`{}`))
}
Now if you wanted, you could put each of those init functions in a separate source file and new commands could be registered by creating a new source file with a new init function.
The rest of the program is simplified with some assumptions that the commands have flat argument lists that the JSON will always encode as an object. This allows you to dispense with separate Go struct definitions for each command. inHandler just creates the same type of object (a map) for all commands, unmarshals into it, and passes it to the command. If you wanted to handle a little more arbitrary JSON, you could unmarshal into an empty interface, and the functions would have to do some extra work to dig out the arguments. If that was too much work and you really wanted to unmarshal directly into a struct, then you arrive near jorelli's solution of making each command function unmarshal its own JSON.
start by defining a function type that does the thing you want:
type Producer func([]byte) interface{}
make a few of them:
func FooProducer(raw []byte) interface{} {
foo := new(Foo)
... // do something to foo
return foo
}
func BarProducter(raw []byte) interface{} {
bar := new(Bar)
... // do something to bar
return bar
}
stick them in a map:
likeThis := map[string]Producer{
"foo": FooProducer,
"bar": BarProducer,
}
and then just do one of these:
myVal := likeThis[someString](raw)
but you probably want to define some interface and make your producer something more like:
type Producer func([]byte) MyAwesomeInterface
since there's probably some common stuff you want to do with those things you're decoding. You also probably want to handle the case of a bad string input, like-a-this:
f, ok := likeThis[someString]
if !ok {
// return, break, panic... something, just get the hell away from here.
}
myVal := f(raw)
The whole notion of inspecting types is kinda cumbersome in Go. It's generally less work to just add new types than it is to try to do reflection gymnastics with the type system.