doufu6130 2016-03-12 20:02
浏览 44
已采纳

GoYAML结构片

I am attempting to learn goyaml, and am having some issues with attempting to produce slices from yaml. I can marshal my struct into this example yaml, but I cannot unmarshal the same yaml back into the struct.

 input:
  file:
  - file: stdin
  webservice:
  - port: "0000"
    address: 0.0.0.0
processing:
  regex:
  - regex: ^(this)*
    mapping: (1) thing
output:
  file:
  - file: stdout
  webservice:
  - port: "0000"
    address: 0.0.0.0

struct:

type Configuration struct{
    Input ioInstance
    Processing ProcessingInstance
    Output ioInstance
}

type ioInstance struct {
    File []FileInstance
    Webservice []WebserviceInstance
}

type FileInstance struct {
    File string
}

type WebserviceInstance struct  {
    Port string
    Address string
}

type ProcessingInstance struct {
    Regex []RegexInstance
}

type RegexInstance struct {
    Regex string
    Mapping string
}

When testing unmarshaling I'm getting reflect errors, as I understand it I think I may need to re-approach the design without struct slices, I was hoping someone could offer some insight into this?

errors:

panic: reflect: reflect.Value.Set using unaddressable value [recovered]
    panic: reflect: reflect.Value.Set using unaddressable value [recovered]
    panic: reflect: reflect.Value.Set using unaddressable value
  • 写回答

1条回答 默认 最新

  • dsgd5756 2016-03-12 20:44
    关注

    The following code works just fine for me, outputting the original yaml text as it should:

    package main
    
    import "fmt"
    import "gopkg.in/yaml.v2"
    
    func main() {
        c := &Configuration{}
        yaml.Unmarshal([]byte(yamlText), c) 
        buf, _ := yaml.Marshal(c)
        fmt.Println(string(buf))
    }
    
    var yamlText = ` 
    input:
      file:
      - file: stdin
      webservice:
      - port: "0000"
        address: 0.0.0.0
    processing:
      regex:
      - regex: ^(this)*
        mapping: (1) thing
    output:
      file:
      - file: stdout
      webservice:
      - port: "0000"
        address: 0.0.0.0
    `
    
    type Configuration struct {
        Input      ioInstance
        Processing ProcessingInstance
        Output     ioInstance
    }
    
    type ioInstance struct {
        File       []FileInstance
        Webservice []WebserviceInstance
    }
    
    type FileInstance struct {
        File string
    }
    
    type WebserviceInstance struct {
        Port    string
        Address string
    }
    
    type ProcessingInstance struct {
        Regex []RegexInstance
    }
    
    type RegexInstance struct {
        Regex   string
        Mapping string
    }
    

    Output:

    input:
      file:
      - file: stdin
      webservice:
      - port: "0000"
        address: 0.0.0.0
    processing:
      regex:
      - regex: ^(this)*
        mapping: (1) thing
    output:
      file:
      - file: stdout
      webservice:
      - port: "0000"
        address: 0.0.0.0
    

    (Of course you should not ignore errors in your actual code, like I'm doing here.)

    EDIT:

    Unmarshal needs a pointer to a struct in order to set its fields. If you call it with a plain struct value, it receives only a copy of the original struct (because in Go everything is passed as a copy), and therefore couldn't possibly alter the fields of the original struct.

    Therefore, you have basically two options:

    You can define and initialize c with c := &Configuration{}, i.e. defining it as a pointer to type Configuration while simultaneously pointing it to a new, zeroed Configuration value. Then you can call yaml.Unmarshal([]byte(yamlText), c).

    Alternatively you can define c with var c Configuration, which means c is not a pointer, but a new zero value of type Configuration. In this case you need to explicitly pass a pointer to that value when you call Unmarshal: yaml.Unmarshal([]byte(yamlText), &c).

    Note that the pointer you pass to Unmarshal must point to an existing Configuration value. var c *Configuration would define c as a pointer, but passing it immediately to Unmarshal would lead to an panic, as it's value is nil; it doesn't point to an existing Configuration value.

    Also, in my code above there was originally a little typo, which is now fixed (though the code still worked). I wrote both c := &Configuration{} and yaml.Unmarshal([]byte(yamlText), &c), so I actually passed Unmarshal a pointer to a pointer to a struct, which Unmarshal was able to handle without issues.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab
  • ¥15 求lingo代码和思路
  • ¥15 公交车和无人机协同运输
  • ¥15 stm32代码移植没反应