<p>I'm new to Go, coming from many years of Java, Python, this and that. I'm having some fits, without a doubt. </p>
<p>My latest head scratcher.... I have a YAML doc with a ton of unrelated config data in it. It's sort of a bad design, but it's not changing, so that's what I'm dealing with.</p>
<p>I don't want to parse the thing as one entity in it's entirety, but instead just be able to grab bits and pieces out of it based on the task at hand. </p>
<p>Given this...</p>
<pre><code>---
service:
apikey: AIzaSyAxVBj5MkKXl_h7RVhK8wlxQnyK0aD9dHU
data:
host: "localhost:9666"
backup: none
password: ~
type GlobalConfig struct {
Service struct {
Apikey string `yaml:"apikey"`
} `yaml:"service"`
Data struct {
Host string `yaml:"host"`
Backup string `yaml:"backup"`
Password interface{} `yaml:"password"`
} `yaml:"data"`
}
</code></pre>
<p>I'd really like to be able to parse out, for example, just the Data struct and ignore the rest. The idea of dealing with this GlobalConfig struct isn't appealing. There are ~five dozen unrelated different "things" detailed in the YAML and a huge struct containing all that data give me shivers. This thing has grown organically from many teams and we're all feeling the pain, though there's little appetite for a proper design.</p>
<p>Any help here? Thanks.</p>
<hr/>**评论:**<br/><br/>binaryblade: <pre><p>The (un)marshallers in go generally ignore extra fields in both your go type and the file. So while you need the wrapper struct, you only need the data field.</p></pre>allhatenocattle: <pre><p>In your example where you just want the data field, you could use:</p>
<pre><code> type DataConfig struct {
Data struct {
Host string `yaml:"host"`
Backup string `yaml:"backup"`
Password interface{} `yaml:"password"`
} `yaml:"data"`
}
</code></pre></pre>allhatenocattle: <pre><p>While I don't understand your situation well, my inclination would be to parse the config once and the pass the configuration sub-elements to the funcs that need it.</p>
<pre><code> type Config struct {
ServiceConfig struct {
Apikey string `yaml:"apikey"`
} `yaml:"service"`
DataConfig struct {
Host string `yaml:"host"`
Backup string `yaml:"backup"`
Password interface{} `yaml:"password"`
} `yaml:"data"`
}
config, err := parseConfig() // parse the whole thing, checking for required elements, set defaults, etc
if err != nil {
log.Fatal(err)
}
someServiceFunc(config.ServiceConfig) // pass in the part of the config the func requires
someDataFunc(config.DataConfig)
</code></pre></pre>Redundancy_: <pre><p>It´s possible that the config is a sort of global config for multiple applications where parts are just not relevant to other applications, otherwise I would tend to agree.</p></pre>allhatenocattle: <pre><p>Good point, in which case the first version would probably be appropriate.</p></pre>kooknboo: <pre><p>Thanks to all that have given some tips. This config doc is in fact some type of global config for a whole slew of unrelated apps. The docs changes daily. Fields are added and removed in a willy nilly fashion. It's a real horror of a design, but that's the way it is. Battling multiple teams and dozens of developers to try to get this on the road to respectibility isn't worth it at this point. Especially since we're hired gone hacking around with Go so they can get a read on whether or not this could be a language of choice for them. Great customer. Odd organization.</p></pre>Emacs24: <pre><p>Take your <code>GlobalConfig</code> structure <a href="https://github.com/go-yaml/yaml" rel="nofollow">and</a></p>
<pre><code>var cfg GlobalConfig
if err := yaml.Parse(input, &cfg); err != nil {
return err
}
</code></pre></pre>kokster_: <pre><p>Hmmm, I'm trying to understand your use case here. Honestly, If the YAML cannot be changed, and you're trying to only parse out some specific parts out of the YAML document, and also Unmarshal it into a typed object, then you'd have to write your own parser for the specific types. However, maintaining this can be more of a tech debt than a super big yaml doc. </p>
<p>If your concern is performance, efficiency, or speed, then you'd be better off by unmarshaling the whole document, and caching it in a quickly accessible location - either in memory/shared memory or over a network. </p>
<p>Then you can choose to retrieve specific subtrees like you wanted. </p>
<p>If you're still looking to just parse out certain parts into typed objects, then like I said, your best bet is to write your own parser for the types you're working with. If you want to do this in a generic fashion such that this would work with any types, then the algorithm for it would be quite involved.</p>
<p>If you already know of an algorithm for such problems, and if you're just looking for implementation help, I'm sure people here, and myself would be able to show you the way. </p></pre>epiris: <pre><p>What do you mean by "The idea of dealing with this GlobalConfig struct isn't appealing"? I would make a "config" package to share across Go apps and just write a tiny abstraction for the unappealing parts and cross-team discrepancies. I.e.: <a href="https://play.golang.org/p/xxz6nCc_Vhq" rel="nofollow">play</a>.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传