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

如何将默认值设置为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
}

Force a method to get the struct (the constructor way). From this post: 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. This can be done by simply making the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something. Another way to customize it for you own module is by using a Config struct to set default values (Option 5 in the link). Not a good way though.


选项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:

有时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"`
}

有一种使用标签的方法 允许多个默认值。

假设您有以下结构,默认有2个 标记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...
}

这是一个操场上的完整程序。

如果你对一个更复杂的例子感兴趣,可以说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值(0表示整型,0.0表示浮点数,""表示字符串,nil表示指针,…)

c := new(Circle)

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

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

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

c := Circle{0, 0, 5}