运行时访问Go中的符号

时间:2016-11-11 14:47:11

标签: go

在Go中编写Web服务器时,我希望能够在运行时取消引用符号,以便让我从配置文件中找出要调用的函数,比如调用虚构的“eval”函数在下面的例子中。这将允许我从处理程序库中选择处理程序,并仅使用配置文件部署新服务器。有没有办法在Go中实现这个目标?

config.json

{ "url": "/api/apple", "handler": "Apple", "method": "get" }
{ "url": "/api/banana", "handler": "Banana", "method": "get" }

play.go

package main

import (
    "github.com/gorilla/mux"
    "net/http"
    "encoding/json"
    "log"
)

type ConfigEntry struct {
    URL string `json:"url"`
    Method string `json:"method"`
    Handler string `json:"handler"`
}

func main() {
    ifp, err := os.Open("config.json")

    if err != nil {
        log.Fatal(err)
    }

    dec := json.NewDecoder(ifp)
    r := mux.NewRouter()

    for {
        var config ConfigEntry

        if err = dec.Decode(&m); err == io.EOF {
            break
        } else if err != nil {
            log.Fatal(err)
        }

        r.HandleFunc(config.URL, eval(config.Handler + "Handler")).Methods(config.Method)
    }

    http.Handle("/", r)
    http.ListenAndServe(8080, nil)
}

func AppleHandler(w http.ResponseWriter, r *http.Request) (status int, err error) {
    w.Write("Apples!\n")
    return http.StatusOK, nil
}

func BananaHandler(w http.ResponseWriter, r *http.Request) (status int, err error) {
    w.Write("Bananas!\n")
    return http.StatusOK, nil
}

2 个答案:

答案 0 :(得分:1)

使用reflect包在运行时访问内容的方式有限。但是,它不允许您在包中搜索所有合适的独立功能。如果它们都是已知结构类型/值的所有方法,那将是可能的。

作为您给定示例的替代方法,您可以简单地使用map[string]func(...)来存储所有处理程序,在启动时(在init()期间)初始化它并从那里获取处理程序。但这也或多或少都是现有的http多路复用器正在做的事情。

答案 1 :(得分:1)

在Go中没有像eval那样的东西,这是一件好事,因为这样的事情是非常危险的。

您可以做的是将配置文件中的处理程序字符串映射到代码中的处理函数:

var handlers = map[string]func(http.ResponseWriter, *http.Request) (int, error){
        "Apple": AppleHandler,
        "Banana": BananaHandler,
}

然后您只需执行以下操作即可注册这些处理程序:

handler, ok := handlers[config.Handler]
if !ok {
        log.Fatal(fmt.Errorf("Handler not found"))
}
r.HandleFunc(config.URL, handler).Methods(config.Method)