如果我有一个假设的结构:
type Config struct {
Server struct {
Host string
Port uint16
Timeout uint32
}
}
我想知道主机和端口是否已设置或默认(主机为“”,端口或超时为0)。有没有一种有效的方法来做到这一点?可能使用反射库?
另外,我假设“”和0是有效的条目。
一些背景知识:我正在使用gcfg库来读取INI样式的配置文件,并想知道是否有人没有设置其中一个配置条目。
答案 0 :(得分:2)
你做不到。至少如果我对你的问题的理解是正确的:
你想知道,例如如果有人故意设置Timeout = 0
或者Timeout是否为零,因为运行时将Timeout初始化为uint32的零值?
如果在此uint32中存储了0,则无法区分“此0是由某个用户通过执行Timeout = 0
设置的”。和“在初始化结构期间,此0是由运行时设置的”。只有一个0,这个0没有历史记录。
如果您需要来区分,可以将Timeout uint32
更改为Timeout *uint32
:运行时将Timeout初始化为nil。如果超时是非零,则设置。 (但这带来了无处不在的nil检查的明显代价,额外的错误处理和复杂的处理。)
答案 1 :(得分:2)
我猜你正在使用gcfg - 当我开始使用gcfg时,我有一个非常相似的问题。我的解决方案是显式加载我的默认值,然后将文件加载到它们上面。
Here's mine;享受。
答案 2 :(得分:0)
不是直接的答案,而是这类问题的常见替代方案:
使用nil指针表示对未初始化结构的引用。如果您计划将结构传递给ini解析器
,则无论如何都需要指针ini解析器(或使用反射的任何解析器)将不会触及传递的指针,除非它可以解析某些东西,在这种情况下它将创建指向类型的新实例并更改指针以定位新解析的数据结构。
http://play.golang.org/p/VkkXSuqbhi
package main
import "fmt"
type Config struct {
Server struct {
Host string
Port uint16
Timeout uint32
}
}
func main() {
var c *Config
fmt.Println(nil == c)
c = &Config{}
fmt.Println(nil == c)
}
答案 3 :(得分:0)
以下内容可能会增加您想要的复杂性,但是,只是让您了解所有选项:
Gcfg的文档声称(我自己实际上并没有这样做)它通过fmt.Scanner接口提供了另一种选择。您声明的任何命名类型都可以从INI文件中解析,只要它实现fmt.Scanner。
考虑到这一点,如果您愿意,可以按照以下方式做一些事情:
package main
import (
"fmt"
"strconv"
"strings"
)
type OptionalInt struct {
IsSet bool
Value int
}
//This method definition is rather impromptu and may not be the best way to scan an int
func (optInt *OptionalInt) Scan (state fmt.ScanState, verb rune) (err error) {
var token []byte
var n int
token, err = state.Token(true, nil)
if err==nil {
n, err = strconv.Atoi(string(token))
if err==nil{
optInt.Value = n
optInt.IsSet = true
}
}
return
}
type Config struct {
Port OptionalInt
TimeOut OptionalInt
}
func main(){
//whatever...
}
如果这样做,那么,一旦将INI文件中的所有数据加载到Config结构中,数据将显示在一组OptionalInt字段中。对于每个这样的字段,您将能够检查IsSet以及内部的值。
如果这种方法对你有吸引力并且你最终尝试了它,也许你可以在这里发表评论,这样我们其他人就会知道它是如何运作的。
答案 4 :(得分:-1)
摆脱gcfg并使用iniflags的标准go标志。这将允许您删除其他答案中提到的一堆hackish代码,并使您的go代码更加惯用,同时支持开箱即用的每个配置值的默认值和描述。