英文:
Differentiate between "No Key" and "No Values" while deserialising/unmarshalling a Yaml list to Golang struct
问题
我正在将一个Yaml配置文件解组为Golang结构体。我想要实现以下逻辑:
如果Yaml中没有黑名单键:
则允许所有内容
否则,如果Yaml中有黑名单键但没有值:
则阻止所有内容
否则,如果Yaml中有黑名单值:
则仅过滤出列出的项目
我无法区分最后两种情况。
实质上,它们看起来相同,即“黑名单键没有值”,但我想知道是否有可能区分它们(不引入任何额外的标志在Yaml中)。
我尝试使用指针类型,但它对此无效。
这是简化的代码示例:
https://play.golang.org/p/UheBEPFhzsg
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type Config struct {
Host string `yaml:"host"`
Blacklist []string `yaml:"blacklist"`
}
func main() {
configDataWithBlacklistValues := `
host: localhost
blacklist:
- try
- experiment
`
configDataWithoutBlacklistValues := `
host: localhost
blacklist:
`
configDataWithoutBlacklistKey := `
host: localhost
`
var configWithBlacklistValues Config // 这个配置应该过滤掉黑名单项目
var configWithoutBlacklistValues Config // 这个配置应该过滤掉所有内容(没有黑名单值 = 所有内容都在黑名单中)
var configWithoutBlacklistKey Config // 这个配置不应该过滤任何内容(没有黑名单键 = 没有内容在黑名单中)
yaml.Unmarshal(([]byte)(configDataWithBlacklistValues), &configWithBlacklistValues)
yaml.Unmarshal(([]byte)(configDataWithoutBlacklistValues), &configWithoutBlacklistValues)
yaml.Unmarshal(([]byte)(configDataWithoutBlacklistKey), &configWithoutBlacklistKey)
fmt.Printf("%+v\n", configWithBlacklistValues)
fmt.Printf("%+v\n", configWithoutBlacklistValues)
fmt.Printf("%+v\n", configWithoutBlacklistKey)
/*
如果Yaml中没有黑名单键:
则允许所有内容
否则,如果Yaml中有黑名单键但没有值:
则阻止所有内容
否则,如果Yaml中有黑名单值:
则仅过滤出列出的项目
*/
}
带有列表作为指针类型的代码示例。
https://play.golang.org/p/wK8i3dLCHWQ
type HostList []string
type Config struct {
Host string `yaml:"host"`
Blacklist *HostList `yaml:"blacklist"`
}
英文:
I am unmarshalling a Yaml config file to Golang struct. I want to implement following logic:
if blacklist key is not there in yaml:
then allow everything
else if blacklist key is there but there are no values:
then block everything
else if blacklist values are there in yaml:
then filter out only the listed items
I'm not able to differentiate between the last two scenarios.
Essentially both look same i.e. "there is no value for blacklist key" but I'm wondering if there's any way possible. (without introducing any additional flag in yaml).
I tried with pointer type but it doesn't work with that.
Here's the simplified code sample:
https://play.golang.org/p/UheBEPFhzsg
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type Config struct {
Host string `yaml:"host"`
Blacklist []string `yaml:"blacklist"`
}
func main() {
configDataWithBlacklistValues := `
host: localhost
blacklist:
- try
- experiment
`
configDataWithoutBlacklistValues := `
host: localhost
blacklist:
`
configDataWithoutBlacklistKey := `
host: localhost
`
var configWithBlacklistValues Config // this config should filter out blacklist items
var configWithoutBlacklistValues Config // this config should filter out everything (no blacklist values = everything to blacklist)
var configWithoutBlacklistKey Config // this config should filter out nothing (no blacklist key = nothing to blacklist)
yaml.Unmarshal(([]byte)(configDataWithBlacklistValues), &configWithBlacklistValues)
yaml.Unmarshal(([]byte)(configDataWithoutBlacklistValues), &configWithoutBlacklistValues)
yaml.Unmarshal(([]byte)(configDataWithoutBlacklistKey), &configWithoutBlacklistKey)
fmt.Printf("%+v\n", configWithBlacklistValues)
fmt.Printf("%+v\n", configWithoutBlacklistValues)
fmt.Printf("%+v\n", configWithoutBlacklistKey)
/*
if blacklist key is not there in yaml:
then allow everything
else if blacklist key is there but there are no values:
then block everything
else if blacklist values are there in yaml:
then filter out only the listed items
*/
}
Codesample with list as pointer type.
https://play.golang.org/p/wK8i3dLCHWQ
type HostList []string
type Config struct {
Host string `yaml:"host"`
Blacklist *HostList `yaml:"blacklist"`
}
答案1
得分: 2
一个简单的解决方法是实现指针类型HostList
,但将2)情况的YAML编码为不包含黑名单值的形式,如下所示:
host: localhost
blacklist: []
这样做,你的解码函数将返回一个长度为零的切片([]string{}
),而不是一个空切片。因此,你的代码可以仅检查第3种情况下的空切片。
英文:
A simple workaround for your solution, would be to implement the pointer type HostList
, but encode the 2) case YAML, i.e. data without blacklist values as below
host: localhost
blacklist: []
By doing so, your unmarshal will return a zero length slice ([]string{}
) and not a nil slice. So your code can check for nil slice for the 3rd case alone.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论