确定结构体是否已初始化

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

Determine if struct is initialised

问题

如果我有一个假设的结构体:

type Config struct {
        Server struct {
                Host string
                Port uint16
                Timeout uint32
        }
}

我想知道Host和Port是否已设置或默认(Host为"",Port或Timeout为0)。有没有一种高效的方法来做到这一点?可能使用reflect库?

另外,我假设""和0是有效的输入。

一些背景信息:我正在使用gcfg库读取一个INI风格的配置文件,并想知道是否有人没有设置其中一个配置项。

英文:

If I have a hypothetical struct:

type Config struct {
        Server struct {
                Host string
                Port uint16
                Timeout uint32
        }
}

I want to know whether the Host and the Port are set or are defaulting (Host to "" and Port or Timeout to 0). Is there an efficient way to do this? Potentially using the reflect library?

Also, I am assuming that "" and 0 are valid entries.

Some background: I am using the gcfg library to read an INI style config file and want to know if someone has not set one of the configuration entries.

答案1

得分: 2

你不能这样做。至少如果我对你的问题的理解是正确的:

你想知道例如是否有人故意设置了Timeout = 0,还是Timeout为零是因为运行时将Timeout初始化为uint32的零值?

如果0存储在这个uint32中,你无法区分“这个0是通过执行Timeout = 0来设置的”和“这个0是在初始化结构时由运行时设置的”。只有一个0,这个0没有历史记录。

如果你_需要_区分,你可以将Timeout uint32更改为Timeout *uint32:运行时将Timeout初始化为nil。如果Timeout非nil,则表示已经设置了Timeout。(但这会带来明显的代价,需要在各处进行nil检查,额外的错误处理和复杂的处理。)

英文:

You can't do that. At least if my understanding of your problem is correct:

You want to know e.g. if someone intentionally set Timeout = 0 or whether Timeout is zero because the runtime initialized Timeout to the zero value of uint32?

If 0 is stored in this uint32 you cannot distinguish between "This 0 was set by some user by executing Timeout = 0." and "This 0 was set by the runtime during initializing the structure." There is just one 0 and this 0 has no history.

If you need to tell the difference you could change Timeout uint32 to Timeout *uint32: The runtime initializes Timeout to nil. If Timeout is non-nil its was set. (But this comes with the obvious price of nil checks everywhere, additional error handling and complicated handling.)

答案2

得分: 2

我猜你正在使用gcfg - 当我开始使用gcfg时,我也有一个非常类似的问题。我的解决方案是显式加载我的默认值,然后在它们上面加载文件。

这是我的解决方案;希望你喜欢。

英文:

I guess you're using gcfg - I had a very similar question when I started using gcfg. My solution was to load my defaults explicitly, then load the file(s) over them.

Here's mine; enjoy.

答案3

得分: 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)
}
英文:

Not a direct answer but a common alternative to this kind of problems:

Use a nil-pointer to represent a reference to an uninitialized structure. You'll need a pointer anyways if you plan to pass the structure to an ini parser

The ini parser (or any parser that uses reflection) will not touch the passed pointer unless it can parse something, in which case it will create a new instance of the pointed-to type and change the pointer to target the newly parsed data structure.

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)
}

答案4

得分: 0

以下可能会比你想要的更加复杂,但是为了让你了解所有的选项:

Gcfg的文档声称(我自己还没有实际尝试过)它通过fmt.Scanner接口提供了另一种选择。只要实现了fmt.Scanner接口的任何命名类型都可以从INI文件中解析出来。

考虑到这一点,如果你愿意,你可以按照以下方式做一些事情:

package main
import (
    "fmt"
    "strconv"
    "strings"
)
type OptionalInt struct {
    IsSet bool
    Value int
}

//这个方法定义是相当即兴的,可能不是扫描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(){
    //随便写点什么...
}

如果你这样做,一旦你将所有数据从INI文件加载到Config结构中,数据将出现在一组OptionalInt字段中。对于每个这样的字段,你将能够检查IsSet以及内部的Value。

如果你对这种方法感兴趣并尝试了它,也许你可以在这里发表评论,这样我们其他人就会知道它的效果如何。

英文:

The following would probably add more complexity than you want but, just so you're aware of all the options:

Gcfg's documentation claims(I haven't actually done it myself) that it provides one more alternative, by way of the fmt.Scanner interface. Any named type that you declare can be parsed from the INI file, so long as it implements fmt.Scanner.

With this in mind, you could, if you felt like it, do something along the lines of the following:

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...
}

If you do this then, once you've loaded all the data from the INI file into your Config structure, the data will appear in a set of OptionalInt fields. And for each such field, you will be able to check IsSet, as well as the Value inside.

If this approach appeals to you and you end up trying it, maybe you could post a comment here so that the rest of us will know how it works out.

答案5

得分: -1

使用标准的go flags替换gcfg,并使用iniflags。这将允许您删除其他答案中提到的一堆hackish代码,并使您的go代码更符合惯用法,同时支持每个配置值的默认值和描述。

英文:

Get rid of gcfg and use standard go flags with iniflags. This will allow you removing a bunch of hackish code mentioned in other answers and make your go code more idiomatic, while supporting default values and descriptions for each config value out-of-the-box.

huangapple
  • 本文由 发表于 2013年5月30日 13:50:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/16828869.html
匿名

发表评论

匿名网友

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

确定