While I was reading "the little go" book, I found that it suggests to write a function without any return value. So I proceed to test that function but the program won't compile and give me this "... used as value"error. Anyone knows what is going on here?
package main
import (
"fmt"
)
func log(message string) {
fmt.Println(message)
}
func main() {
msg := log("just a message")
fmt.Println(msg)
}
I know that this function is trivial (maybe the question is stupid also). But I am just curious to know if this type of function legal in Go?
The function here you have used
func log(message string){
fmt.Println(message)
}
Actually returns nothing.
But you are assigning it to a variable is incorrect. Since function returns nothing.
msg := log("just a message")
and that's why the error
.. used as value
You can call it directly.
func main() {
log("just a message")
}
Check out on go playground
A function that returns nothing is perfectly valid:
func log(message string) {
// .. do stuff
}
But treating it as though it returns something is invalid:
msg := log("foo") // what do you expect to be assigned to msg? log() returns nothing!
Your log() function does not return anything so you can’t assign it result to a variable (msg := ...)
import(
"fmt"
)
func log(message string){
fmt.Println(message)
}
func main(){
log("just a message")
}
Related
I want to pass a variadic function as the parameter of another function.I tried like the following code, but it didn't work.Please give me some of advice.
type Action func(args ...any) error
func ActionType(f Action) reflect.Type {
return reflect.TypeOf(f)
}
func main() {
f1 := func(int, string) error {}
f2 := func(int) error {}
f3 := func() error {}
fmt.Println(ActionType(f1), ActionType(f2), ActionType(f3)) //error here
}
You're declaring f1, f2, and f3 as anonymous functions with types func(int,string) error, func(int) error, and func() error respectively, none of which is func(...any) error. To create an Action you'd have to do f4 := func(...any) error { //stuff } for example. Types are pretty strict in Go, and its variadic functions are basically just syntactic sugar for accepting a single slice argument (as the last arg). Roughly, func(...any) equals func([]any), though even these aren't even the same type.
The error messages basically tell you this, though more tersely.
./prog.go:18:25: cannot use f1 (variable of type func(int, string) error) as type Action in argument to ActionType
./prog.go:18:41: cannot use f2 (variable of type func(int) error) as type Action in argument to ActionType
./prog.go:18:57: cannot use f3 (variable of type func() error) as type Action in argument to ActionType
Icza suggested in the comments one way to make ActionType() take any function. Another way that I have used before, and is perhaps a little more type safe, is to make ActionType() take a function with no arguments (and return an error, or whatever else you need to return). Then, use a closure to capture the "arguments" for the Action func. For example:
package main
import (
"fmt"
"reflect"
)
type Action func() error
func ActionType(f Action) reflect.Type {
// call f to perform the action
err := f()
if err != nil {
fmt.Println(err)
}
// do other things ...
return reflect.TypeOf(f)
}
// this is essentially the same since Action's underlying type
// is "func() error"
func ActionType2(f func() error) reflect.Type { return reflect.TypeOf(f) }
func main() {
msg := "hello world"
number := 42
action1 := func() error {
fmt.Println(msg)
return nil
}
action2 := func() error {
number *= 2
return nil
}
fmt.Println(ActionType(action1))
fmt.Println(ActionType(action2))
fmt.Println(ActionType2(action2)) // doesn't modify number
fmt.Println(number)
}
Output
hello world
main.Action
main.Action
func() error
84
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.
I am a newbie at GO Programming. Here is scenario :-
There exists a JSON file that looks like this :-
{
"template": "linuxbase1",
"checkname": ["check_disk"],
"checkmethod": ["check_disk"]
}
I am Unmarshalling this data into a structure :-
package func1
import (
"io/ioutil"
"os"
"encoding/json"
"fmt"
)
type pluginfunc func() string
type Plugindata struct {
Template string `json:"template"`
Checkname []string `json:"checkname"`
Checkmethod []pluginfunc `json:"checkmethod"`
}
var (
Templatepath = "json_sample1.json"
Templateitems Plugindata
)
func Gettemplatedata() {
tdata, err := ioutil.ReadFile(Templatepath)
if err != nil {
fmt.Printf("Unable to read file %s. Error - %v\n",Templatepath, err.Error())
os.Exit(3)
}
json.Unmarshal(tdata, &Templateitems)
}
The "check_disk" function is here :-
package func1
func check_disk() string {
return "Called check_disk"
}
This is the program with main() :-
package main
import (
"fmt"
"checksexpt/func1"
)
func main() {
func1.Gettemplatedata()
fmt.Printf("Templateitems in Main() => %v\n",func1.Templateitems)
for index,funcname := range func1.Templateitems.Checkmethod {
fmt.Printf("%d = %s\n",index,funcname())
}
}
As expected, when I run main(); I see the error :-
Templateitems in Main() => {linuxbase1 [check_cpu check_disk] [<nil> <nil>]}
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x40115e]
goroutine 1 [running]:
panic(0x50e980, 0xc82000a100)
/opt/go/src/runtime/panic.go:481 +0x3e6
So, I am trying to grab a string from the JSON file and treat it as a function call. That obviously fails ! But, the primary constraint here is that the function names have to be picked from the JSON file. How can I do this ? I know that I can create a static map as follows :-
type checkfunc func() string
var (
Templateitems = map[string]map[string]checkfunc {
"linuxbase1": {
"check_disk": check_disk,
},
}
)
So, A call like - Templateitems["linuxbase1"]["check_disk"]() would work just fine. But, I dont want to create any such static map as the elements in that map needs to keep growing. Any ideas on this?
There is no direct way to parse a function directly from a JSON value. Also, you cannot use string values to refer to variables. So a string check_cpu would not be able to refer to the function with the same name directly.
What you can do instead is parse the json string as is and have a global map for functions. That way, you can call your functions like so:
var funcMap = map[string]pluginfunc{
"check_disk": check_disk,
"check_cpu": check_cpu
}
In your main loop:
for index, funcname := range func1.Templateitems.Checkmethod {
fmt.Printf("%d = %s\n", index, funcMap[funcname]())
}
If however, you really need to put the value in your structure, you can try implementing UnmarshalJSON from the json.Unmarshaler interface. A simple example would be:
type pf map[string]pluginfunc
type Plugindata struct {
Template string `json:"template"`
Checkname []string `json:"checkname"`
Checkmethod pf `json:"checkmethod"`
}
func (p *pf) UnmarshalJSON(data []byte) error {
d := []string{}
if err := json.Unmarshal(data, &d); err != nil {
return err
}
*p = make(pf)
for _, s := range d {
(*p)[s] = funcMap[s]
}
return nil
}
var funcMap = pf{
"check_disk": check_disk,
"check_cpu": check_cpu
}
func main() {
json.Unmarshal(tdata, &Templateitems)
for k, f := range Templateitems.Checkmethod {
fmt.Printf("%s -- %s\n", k, f())
}
}
Working code
Note that this way is not as readable or simple as the first method and it still relies on a function map.
You can read more about json.Unmarshaler here.
Here's what I'm trying to do:
package products
ProductManager struct {
products []*Product
index int64
}
func NewPM() *ProductManager {
return &ProductManager{}
}
func (p *ProductManager) List() []*Product {
return p.products
}
---
var productManager = products.NewPM()
func main() {
api := Api{}
api.Attach(productManager, "/products")
}
func (api Api) Attach(rm interface{}, route string) {
// Apply typical REST actions to Mux.
// ie: Product - to /products
mux.Get(route, http.HandlerFunc(index(rm)))
}
func index(rm interface{}) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// allRecords := rm.List() - DOESN'T WORK. No method found.
result := reflect.TypeOf(rm) // Works, shows me the correct type.
method := result.Method(0).Name // Works as well! Shows me a function on the type.
w.Write([]byte(fmt.Sprintf("%v", method)))
}
}
Any idea on why I can't call the List() function on my productManager object? I can see the Type's functions and even get the right Type name in the index() handler.
Dead simple: rm is an empty interface variable, so it does not have any methods, that's exactly what interface{} means: No methods. If you know that rm's dynamic type is *ProductManager you can type assert it (but than you could pass a *ProductManager) Maybe you'll have to type switch on rm in the longer run. (BTW: using interface{} is almost always a bad idea.)
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.