如何在Go结构设置默认值

以下问题有多种答案/技巧:

  1. 如何将默认值设置为golang结构?
  2. 如何初始化结构在golang

我有几个答案,但还需要进一步讨论。

294164 次浏览

一种可能的想法是编写单独的构造函数

//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
}
  1. 强制一个方法获取结构(构造函数方式)。

    这篇文章:

    一个好的设计是让你的类型不导出,但提供一个导出的构造函数,如NewMyType(),在其中你可以正确地初始化你的结构/类型。还要返回一个接口类型,而不是一个具体类型,并且接口应该包含其他人想要用您的值做的所有事情。当然,您的具体类型必须实现该接口。

    这可以通过简单地使类型本身未导出来实现。您可以导出函数NewSomething,甚至字段Text和DefaultText,但不要导出结构类型something。

  2. 为你自己的模块定制它的另一种方法是使用配置struct设置默认值(链接中的选项5)。但这不是一个好方法。

答案中选项1的一个问题 Victor Zamanian认为,如果没有导出类型,那么包的用户就不能将其声明为函数参数的类型等。解决这个问题的一种方法是导出一个接口而不是结构体,例如

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接口声明函数参数类型。 我能从这个解决方案中看到的唯一缺点是,我们所有的方法都需要在接口定义中声明,但你可能会说这是一种很好的实践

From https://golang.org/doc/effective_go.html#composite_literals:

有时0值还不够好,需要初始化构造函数,就像这个从包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
}
type Config struct {
AWSRegion                               string `default:"us-west-2"`
}

有一种方法可以用标签来做到这一点 允许多个默认值。< / p > 假设你有下面的struct,默认为2 标记default0default1。< / p >

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

这里是在操场上完成项目

如果你对一个更复杂的例子感兴趣,可以说with 切片和映射,那么,看一下creasty / defaultse

其中一种方法是:

// declare a type
type A struct {
Filed1 string
Field2 map[string]interface{}
}

因此,每当你需要一个自定义类型的新变量时,只需调用NewA函数,你也可以将函数参数化,可选地将值分配给struct字段

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(人)

做这样的东西怎么样:

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

结构体

使这个程序更好的一个简单方法是使用结构体。struct是一种包含命名字段的类型。例如,我们可以这样表示一个圆:

type Circle struct {
x float64
y float64
r float64
}

type关键字引入了一个新类型。后面跟着类型的名称(Circle)、关键字struct(表示我们正在定义结构类型)和花括号内的字段列表。每个字段都有一个名称和类型。像函数一样,我们可以折叠具有相同类型的字段:

type Circle struct {
x, y, r float64
}

初始化

我们可以用多种方式创建Circle类型的实例:

var c圆 与其他数据类型一样,这将创建一个默认设置为0的本地Circle变量。对于结构体,0表示每个字段都被设置为相应的0值(int为0,float为0.0,""我们还可以使用新的函数

c := new(Circle)

这将为所有字段分配内存,将每个字段设置为0值并返回一个指针。(*圆圈)更多时候,我们想给每个字段一个值。我们可以用两种方法做到这一点。是这样的:

c := Circle{x: 0, y: 0, r: 5}

或者,如果我们知道字段的定义顺序,我们可以省略字段名:

c := Circle{0, 0, 5}