Generic function using an interface - function

Since I've a similar function for 2 different data types:
func GetStatus(value uint8) (string) {...}
func GetStatus(name string) (string) {...}
I would want to use a way more simple like:
func GetStatus(value interface{}) (string) {...}
Is possible to create a generic function using an interface?
The data type could be checked using reflect.Typeof(value)

Does what you want to do need the complexity and overhead of the reflect package? Have you considered a simple switch statement type switch?
package main
import (
"fmt"
)
func GetStatus(value interface{}) string {
var s string
switch v := value.(type) {
case uint8:
v %= 85
s = string(v + (' ' + 1))
case string:
s = v
default:
s = "error"
}
return s
}
func main() {
fmt.Println(GetStatus(uint8(2)), GetStatus("string"), GetStatus(float(42.0)))
}

Related

How to add multiple values returned by a function directly

I have the following code.
package main
import "fmt"
func main() {
a := 0
b := 0
a, b += getValues()
fmt.Println(a, b)
}
func getValues() (a int, b int) {
a = 0
b = 5
return
}
I want to directly add the multiple values returned by a function. I just want to if there is a provision like this in Go.
When I run the above code, I get the following error.
syntax error: unexpected +=, expecting := or = or comma
You can use a helper method which takes a variadic number of parameters and just returns the slice created from the params
func aggregator(res ...interface{}) []interface{}{
return res
}
If you want to escape the extra type assertion you can set the type you want to work with, in your case int, for the input and output parameters of the helper function. But here is an example using interface{}:
func main() {
fmt.Printf("%d, %d", aggregator(f())[0].(int), aggregator(f())[1].(int))
}
func aggregator(res ...interface{}) []interface{}{
return res
}
func f () (int, int) {
return 1,2
}
Go Playground.

How do I preprocess rows fetched with sqlx?

Consider the following example:
package main
import (
"fmt"
"github.com/jmoiron/sqlx"
_ "github.com/go-sql-driver/mysql"
)
type Data struct {
Stuff string
}
func main() {
db, _ := sqlx.Connect("mysql", "root:root#(localhost:3306)/data")
var datas []Data
db.Select(&datas, "select 'a,b' stuff from data limit 10")
fmt.Println(datas)
}
What I'd like to do is have Stuff as []string, where it would be split by ,. I guess I could add an extra []string field and loop over the results populating this field and removing the source data, but that seems inefficient. What's the canonical way to do this in sqlx?
While this is not supported out of the box you can create custom struct implementing Scanner interface (https://golang.org/pkg/database/sql/#Scanner):
type StringList []string
// Scan implements Scanner interface and parses
// database result to StringList struct.
func (s *StringList) Scan(src interface{}) error {
var source string
switch src.(type) {
case string:
source = src.(string)
case []byte:
source = string(src.([]byte))
default:
return errors.New("Incompatible type for StringList")
}
*s = strings.Split(source, ",")
for i := range *s {
(*s)[i] = strings.TrimSpace((*s)[i])
}
return nil
}
And use this struct instead of string:
type Data struct {
Stuff StringList
}

Golang Function Call in Map

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.

go pass dynamically created function as parameter

Ok. I have some trouble understanding what exactly is going on here with "MyPrinter"
Let me go step by step (please correct me if got something wrong)
1. The "Salute" structure is created
2. Call to "Greet" function
2.a Call to "CreatePrinterFunction" with the strgin "!!!". This function returns a "MyPrinter" (witch is a function that takes in a string and returns nothing)
3. the variables "message" and "defaultMessage" are set with the strings
Now here's the problem, I don't understand what exactly are those do("str") doing
package main
import "fmt"
type Salute struct {
name string
greeting string
}
type MyPrinter func (s string) ()
func Greet(salute Salute, do MyPrinter) {
message, defaultMessage := CreateMessage(salute.name, salute.greeting, "noName")
do(message)
do(defaultMessage)
}
func Print(s string) {
fmt.Print(s)
}
func PrintLine(s string) {
fmt.Println(s)
}
func CreatePrinterFunction(custom string) MyPrinter {
return func (s string) {
fmt.Println(s + custom)
}
}
func CreateMessage(name string, greeting ...string) (message string, defaultMessage string) {
message = name + " " + greeting[0]
defaultMessage = "hey " + name
return
}
func main() {
var s = Salute{"Joe", "hello"}
// Greet(s, PrintLine)
Greet(s, CreatePrinterFunction("!!!"))
}
CreatePrinterFunction returns a function literal:
return func (s string) {
fmt.Println(s + custom)
}
That function literal implements the MyPrinter interface, which is an interface implemented by any function that takes a string argument and returns nothing:
type MyPrinter func(s string)
(note that the MyPrinter definition in the provided snippet includes an extra () at the end which does nothing)
Then, that function created which implements the MyPrinter interface is passed as the do parameter of the Greet function:
func Greet(salute Salute, do MyPrinter) {
When code inside Greet runs do(message), the created function literal is called, which in its turn runs the equivalent of fmt.Println(message + custom).
It's a pretty convoluted way to do something simple. :-)

Dynamically create variables of certain type based on string in Go

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.