Differentiate between "No Key" and "No Values" while deserialising/unmarshalling a Yaml list to Golang struct

huangapple go评论91阅读模式
英文:

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种情况下的空切片。

Go Playground

英文:

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.

Go Playground

huangapple
  • 本文由 发表于 2021年9月20日 16:31:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/69251318.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定