- 如何为Golang结构设置默认值?
- 如何在Golang中初始化结构
一个可能的想法是编写单独的构造函数
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
NewSomething
甚至字段Text
和DefaultText
,但请勿导出结构体类型something
本身。 - Amit Kumar Guptareflect.New()
实例化结构体),问题会变得更加严重,因为无法期望该库知道你特别命名的工厂函数。在这种情况下,除非改变语言本身,否则仅靠接口(库可以检查接口)才能解决问题。 - edam强制使用构造函数来获取结构体。
根据这篇文章的说法:
一个好的设计是使您的类型未导出,但提供一个导出的构造函数如
NewMyType()
,在其中您可以正确地初始化您的结构体/类型。还返回一个接口类型而不是具体类型,并且该接口应包含其他人想要对您的值进行的所有操作。 当然,您的具体类型必须实现该接口。
这可以通过将类型本身设置为未导出来完成。 您可以导出NewSomething函数甚至Text和DefaultText字段,但只要不导出struct类型something即可。
另一种自定义方法是使用配置结构体来设置默认值 (选项5),但并不是好的方式。
NewMyType()
,在其中您可以正确地初始化您的结构/类型。...这样您就不必担心不正确的初始化了。” - starrietVictor Zamanian的答案中选项1存在一个问题,如果该类型未导出,则您软件包的用户无法将其声明为函数参数等的类型。解决此问题的一种方法是导出接口而不是结构体。
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
return candidate{name, 0} // enforce the default value here
}
我们可以使用导出的Candidate接口声明函数参数类型。我唯一能看到这种解决方案的劣势是,所有方法都需要在接口定义中声明,但你可以认为这是一个好习惯。
Name
和Votes
字段大写可能会让人感到困惑。它们可能对于json.Marshal或类似的反射操作很有用,但对于正常访问来说,小写字段一样好用。interface
无法导出字段,只能导出方法(即需要方法才能使用)。 - kubanczyk有一种使用标签的方法可以实现这一点,允许拥有多个默认值。
假设你有以下结构体,其中包含两个默认标签default0和default1。
type A struct {
I int `default0:"3" default1:"42"`
S string `default0:"Some String..." default1:"Some Other String..."`
}
现在可以设置默认值。
func main() {
ptr := &A{}
Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...
Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}
这里是在Playground中的完整程序:https://play.golang.org/p/rFql2x0Klm4
如果你对更复杂的例子感兴趣,比如使用切片和映射表,可以看一下creasty/defaultse
golang
。你有一个使用反射的通用构造函数。一个真正的默认值会在每个新结构体实例上自动设置。 - ton来自 https://golang.org/doc/effective_go.html#composite_literals:
有时候零值并不够好,需要一个初始化构造函数,就像这个例子从os包中派生出来的一样。
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
做类似这样的东西怎么样:
// Card is the structure we work with
type Card struct {
Html js.Value
DefaultText string `default:"html"` // this only works with strings
}
// Init is the main function that initiate the structure, and return it
func (c Card) Init() Card {
c.Html = Document.Call("createElement", "div")
return c
}
然后按如下方式调用:
c := new(Card).Init()
我发现这个帖子非常有帮助和教育意义。其他回答已经提供了很好的指导,但我想用一种易于参考(即复制粘贴)的方法来总结我的心得体会:
package main
import (
"fmt"
)
// Define an interface that is exported by your package.
type Foo interface {
GetValue() string // A function that'll return the value initialized with a default.
SetValue(v string) // A function that can update the default value.
}
// Define a struct type that is not exported by your package.
type foo struct {
value string
}
// A factory method to initialize an instance of `foo`,
// the unexported struct, with a default value.
func NewFoo() Foo {
return &foo{
value: "I am the DEFAULT value.",
}
}
// Implementation of the interface's `GetValue`
// for struct `foo`.
func (f *foo) GetValue() string {
return f.value
}
// Implementation of the interface's `SetValue`
// for struct `foo`.
func (f *foo) SetValue(v string) {
f.value = v
}
func main() {
f := NewFoo()
fmt.Printf("value: `%s`\n", f.GetValue())
f.SetValue("I am the UPDATED value.")
fmt.Printf("value: `%s`\n", f.GetValue())
}
Value() string
和 SetValue(string)
。请参见 https://go.dev/doc/effective_go#Getters。 - bestbeforetoday这样做的方式是:
// declare a type
type A struct {
Filed1 string
Field2 map[string]interface{}
}
func NewA() *A {
return &A{
Filed1: "",
Field2: make(map[string]interface{}),
}
}
在Go结构体中设置默认值,我们使用匿名结构体:
Person := struct {
name string
age int
city string
}{
name: "Peter",
age: 21,
city: "Noida",
}
fmt.Println(Person)