【问题标题】:How to set default values in Go structs如何在 Go 结构中设置默认值
【发布时间】:2016-09-05 05:38:12
【问题描述】:

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

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

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

【问题讨论】:

  • @icza 您的回答确实提供了一种方法,但是按照问题标题,它绝不相似或可搜索,因为它是一个非常具体的问题。不过,我会在我的答案中添加链接。
  • 这里有两个问题,选一个。假设您选择第一个问题(根据问题标题),请更具体地说明您之前的研究以及您的其他答案需要更多讨论的地方。

标签: go struct initialization default-value


【解决方案1】:

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

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

【讨论】:

  • 是的,这也是我在回答中提到的一种方式,但我们无法强迫任何人只使用此功能。
  • @Prateek 要么就是这个,要么使用一个界面,这会很丑而且过于复杂。
  • @Prateek 是的,如果您只是将类型本身设为未导出,则可以强制人们使用此构造函数。你可以导出函数NewSomething甚至字段TextDefaultText,但不要导出结构类型something
  • 问题更严重...如果使用第三方(例如库)来实例化您的结构(例如通过reflect.New()),则无法期望它知道你特别命名的工厂函数。在这种情况下,如果不改变语言本身,我认为只有一个接口(库可以检查)就可以了。
  • 设置默认值很好,但有时,我可能想覆盖默认值。在这种情况下,我将无法使用非默认值初始化结构。对我来说有点烦人
【解决方案2】:
  1. 强制方法获取结构体(构造方法)。

    来自this post

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

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

  2. 为您自己的模块定制它的另一种方法是使用Config struct to set default values(链接中的选项5)。不过这不是一个好方法。

【讨论】:

【解决方案3】:

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

【讨论】:

    【解决方案4】:

    来自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
    }
    

    【讨论】:

      【解决方案5】:
      type Config struct {
          AWSRegion                               string `default:"us-west-2"`
      }
      

      【讨论】:

      • 这是不正确的。充其量,您可以在该字段上设置一个标记值,然后通过反射获取其值,但即使这样,语法也不正确(缺少反引号),您只能为字符串类型设置默认值。如果您对这个示例具体指的是什么有所了解,请添加一个链接以供参考。
      【解决方案6】:

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

      假设您有以下结构,默认为 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

      【讨论】:

      • 非常感谢!我开始编写与库建议的代码相同的代码,并遇到了这篇文章。它完全符合您的预期 (github.com/creasty/defaults)。如果您没有值,它会设置默认值,但是如果您为变量分配了值,那么它将不会分配默认值。它与 yaml.v2 库配合得很好。
      • 这是一个不错的选择,但它不是来自golang。您有一个使用反射的通用构造函数。每个新的结构实例都会自动设置一个真正的默认值。
      【解决方案7】:

      一种方法是:

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

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

      func NewA() *A {
          return &A{
              Filed1: "",
              Field2: make(map[string]interface{}),
          }
      }
      

      【讨论】:

        【解决方案8】:

        为了在 Go 结构中设置默认值,我们使用匿名结构:

        Person := struct {
            name      string
            age       int
            city      string
        }{
            name:      "Peter",
            age:        21,
            city:      "Noida",
        }
        

        fmt.Println(人)

        【讨论】:

          【解决方案9】:

          制作这样的东西怎么样:

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

          【讨论】:

            【解决方案10】:

            我发现这个帖子很有帮助和教育意义。其他答案已经提供了很好的指导,但我想用一种易于参考(即复制粘贴)的方法来总结我的观点:

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

            【讨论】:

              猜你喜欢
              • 2021-01-26
              • 2010-11-14
              • 2021-09-22
              • 2020-01-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多