简体   繁体   中英

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM