2016-08-16 25 views
1

我是GO編程的新手。下面是場景: -Golang在地圖上的函數調用

存在一個JSON文件看起來像這樣: -

{ 
     "template": "linuxbase1", 
     "checkname": ["check_disk"], 
     "checkmethod": ["check_disk"] 
} 

我解組這個數據變成結構: -

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) 
} 

的 「check_disk」 功能在這裏: -

package func1 

func check_disk() string { 
     return "Called check_disk" 
} 

這是主要的()程序: -

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()) 
     } 

} 

正如所料,當我運行main();我看到的錯誤: -

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 

所以,我想從JSON文件中抓住一個字符串,並將其視爲一個函數調用。那顯然失敗了!但是,這裏的主要約束是必須從JSON文件中選取函數名稱。我怎樣才能做到這一點 ?我知道,我可以按如下創建靜態地圖: -

type checkfunc func() string 
var (
     Templateitems = map[string]map[string]checkfunc { 
       "linuxbase1": { 
         "check_disk": check_disk, 
       }, 
     } 
) 

因此,像呼喚 - Templateitems["linuxbase1"]["check_disk"]()會工作得很好。但是,我不想創建任何這樣的靜態地圖,因爲該地圖中的元素需要保持增長。對此有何想法?

回答

2

沒有直接從JSON值解析函數的直接方法。另外,您不能使用字符串值來引用變量。所以字符串check_cpu將無法​​直接引用具有相同名稱的函數。

你可以做什麼,而不是解析json字符串,並有一個函數的全球地圖。這樣的話,你可以打電話給你的功能,像這樣:

var funcMap = map[string]pluginfunc{ 
    "check_disk": check_disk, 
    "check_cpu": check_cpu 
} 

在你main循環:

for index, funcname := range func1.Templateitems.Checkmethod { 
     fmt.Printf("%d = %s\n", index, funcMap[funcname]()) 
} 

但是,如果你真的需要把價值在你的結構,你可以嘗試從實施UnmarshalJSON接口json.Unmarshaler。一個簡單的例子是:

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

注意,這種方式並不像可讀或簡單作爲第一方法,它仍然依賴於一個功能地圖上。

您可以閱讀更多關於json.Unmarshalerhere