如何在 Go 结构中设置默认值

How to set default values in Go structs

下面的问题有多个answers/techniques:

  1. 如何为 golang 结构设置默认值?
  2. 如何在 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
}
  1. 强制方法获取结构(构造函数方式)。

    来自

    A good design is to make your type unexported, but provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. Also return an interface type and not a concrete type, and the interface should contain everything others want to do with your value. And your concrete type must implement that interface of course.

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

  2. 另一种为您自己的模块自定义它的方法是使用 Config struct to set default values(link 中的选项 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 接口声明函数参数类型。 我从这个解决方案中看到的唯一缺点是我们所有的方法都需要在接口定义中声明,但你可能会争辩说这是一个很好的做法。

来自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
}
type Config struct {
    AWSRegion                               string `default:"us-west-2"`
}

有一种方法可以用标签做到这一点, 允许多个默认值。

假设您有以下结构,默认有 2 个 标签 default0default1

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

这是complete program in a playground

如果您对更复杂的示例感兴趣,请使用 切片和地图,然后,看看 creasty/defaultse

一种方法是:

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

因此,每当您需要自定义类型的新变量时,只需调用 NewA 函数,您也可以参数化该函数以选择性地将值分配给结构字段

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