我是刚来golang 的,谁能帮我一下吗?我有一个yaml文件,看起来像这样:

port: 5000
handlers:
  - name: test1
    uri: /api/test1
    response:
      status: 200
      body: test1
  - name: test2
    uri: /api/test2
    response:
      status: 500
      body: test2

基于这个文件,我想创建一个服务器.目前,我正试图这样做,但看起来并不像预期的那样.

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"

    "gopkg.in/yaml.v2"
)

func main() {
    config := parseYaml("conf.yaml")
    configHandlers := config.Handlers
    mux := http.NewServeMux()
    for _, handler := range *configHandlers {
        mux.HandleFunc(*handler.Uri, func(w http.ResponseWriter, r *http.Request) {
            w.WriteHeader(*handler.Response.Status)
            fmt.Fprintf(w, *handler.Response.Body)
        })
    }
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", *config.Port), mux))
}

type YamlConfig struct {
    Port     *string          `yaml:"port"`
    Handlers *[]HandlerConfig `yaml:"handlers"`
}

type HandlerConfig struct {
    Uri      *string   `yaml:"uri"`
    Name     *string   `yaml:"name"`
    Response *Response `yaml:"response"`
}

type Response struct {
    Status *int    `yaml:"status"`
    Body   *string `yaml:"body"`
}

func (c *YamlConfig) parseYaml(data []byte) error {
    return yaml.Unmarshal(data, c)
}

func parseYaml(path string) YamlConfig {
    data, err := ioutil.ReadFile(path)
    if err != nil {
        log.Fatal(err)
    }
    var config YamlConfig
    if err := config.parseYaml(data); err != nil {
        log.Fatal(err)
    }
    return config
}

更新:

推荐答案

你看到的似乎是人们常见的trap :

configHandlers := config.Handlers
mux := http.NewServeMux()
for _, handler := range *configHandlers {
    mux.HandleFunc(*handler.Uri, func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(*handler.Response.Status)
        fmt.Fprintf(w, *handler.Response.Body)
    })
}

在每次迭代中,for循环重新分配handler变量.在循环体中,创建一个新函数并将其传递给mux.HandlerFun.这些函数体有点像外部范围,并访问这个handler变量.变量被重新分配到函数之外,因此每个处理函数都可以访问这些值.解决这个问题的方法是屏蔽循环使用的handler变量,并创建一个对每个处理程序都唯一的作用域.在JavaScript这样的语言中,classic 的方法是将代码包装在IIFE中(立即调用函数表达式):

for _, handler := range *configHandlers {
    func (handler *HandlerConfig) { // handler is now the argument passed to this function
        mux.HandleFunc(*handler.Uri, func(w http.ResponseWriter, r *http.Request) {
            w.WriteHeader(*handler.Response.Status)
            fmt.Fprintf(w, *handler.Response.Body)
        })
    }(handler) // call the function with the _current_ value of handler
}

这有点凌乱,因为golang是正确的块范围,所以您可以这样做:

for _, handler := range *configHandlers {
    h := handler // create a variable in the inner scope
    mux.HandleFunc(*handler.Uri, func(w http.ResponseWriter, r *http.Request) {
        // now h will reference a copy unique to each iteration
        w.WriteHeader(*h.Response.Status)
        fmt.Fprintf(w, *h.Response.Body)
    })
}

这应该能解决问题.我注意到你在问题中添加的类型中使用指针有些奇怪,不过...像Port这样的字段属于*string类型?你为什么不用string呢?Response类型中的BodyStatus字段不相同.通过将它们更改为纯string字段,您不必在处理程序函数中取消对它们的引用.它看起来会干净得多.

更令人担忧的是这个领域:

Handlers *[]HandlerConfig `yaml:"handlers"`

我不确定你是否真的知道这个领域的类型,但这几乎毫无意义.Handlers现在是指向HandlerConfig个值的一个片段的指针.我假设你希望这个领域是:

// Handlers is a slice of HandlerConfig values:
Handlers []HandlerConfig `yaml:"handlers"`
// or Handlers is a slice of pointers to HandlerConfig values
Handlers []*HandlerConfig `yaml:"handlers"`

一般来说,在配置类型中,指向片especially的指针是错误的代码.

Go相关问答推荐

如何模拟嵌入. FS?

如何使用Docker Compose配置Go,使main. go文件位于/CMD文件夹中

我不能让GIO画一个按钮

如何将文件从AWS S3存储桶复制到Azure BLOB存储

如何使用工作区方法扩展克隆的Golang库

重新赋值变量时未清除动态类型-这是错误吗?

exec的可执行决议.命令+路径

这种合并排序的实现有什么问题?

使用反射在Go中递归迭代 struct 体和集合字段

在 Go 中解组编号的 XML 标签

MQTT 客户端没有收到另一个客户端发送的消息

如何使用泛型将接口转换为指定类型

访问传递给可变参数函数的通用 struct 的特定字段

查找、解析和验证邮箱地址

有没有办法将 yaml node 添加到 golang 中现有的 yaml 文档中?

NaN 是 golang 中的可比类型吗?

Golang prometheus 显示自定义指标

正确编码 JWT

有没有办法在golang中映射一组对象?

Golang 中的无实体函数