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

  • 如何设置golang结构的默认值?
  • 如何初始化golang中的结构
  • 我有几个答案,但需要进一步讨论。

    • 相关:如何确保在golang中创建对象后使用方法?
    • @icza你的回答确实提供了一种方法来做到这一点,但是按照问题标题,它绝不是类似的或可搜索的,因为它是一个非常具体的问题。 我会在我的回答中添加链接。
    • 这里有两个问题,选择一个。 假设您选择第一个问题(根据问题标题),请更具体地说明您之前的研究以及您的其他答案需要更多讨论的地方。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //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
    • 值得尝试。仍然想知道结构变量是否可以直接访问。将检查出来。谢谢 !!
    • @AmitKumarGupta,这对我来说也是一个新见解)
    • @Amit,我在我的回答中提到了这个扩展 - 它建议使用interface作为返回值
    • 问题更严重......如果使用第三方(例如库)来实例化你的结构(例如,通过reflect.New()),就无法知道你特别命名的工厂函数。在这种情况下,如果语言本身没有被改变,我认为只有一个界面(图书馆可以检查)。
    • 难道你不应该回来和返回类型的东西*一些好的做法?
    • 要添加Amit的一个值,最好使用单例而不是每次都生成结构

  • 强制方法获取结构(构造方式)。

    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,但只是不导出struct类型的东西

  • 为您自己的模块定制它的另一种方法是使用Config结构来设置默认值(链接中的选项5)虽然不是一个好方法。

    • 现在这是一个断开的链接(404):joneisen.tumblr.com/post/53695478114/golang-and-default-values
    • 它可以在后卫机器中使用。
    • FWIW,我认为它是'选项3' - 至少在返回机器链接中。 (那里没有'选项5')。
    • @ m90沉默golint你可以声明你的函数返回公共接口类型
    • @ThomasGrainger我的评论似乎是指这个答案的先前修订版,它实际上没有任何意义这样了:)我将删除它。
    • 报价有什么来源吗?引用这句话使它听起来如此官方。这不是来自链接的博客文章,不幸的是我没有谷歌搜索它。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    package candidate
    // Exporting interface instead of struct
    type Candidate interface {}
    // Struct is not exported
    type candidate struct {
        Name string
        Votes unit32 // 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接口声明函数参数类型。
    我从这个解决方案中可以看到的唯一缺点是我们所有的方法都需要在接口定义中声明,但你可以说这无论如何都是好的做法。

    • 可以在调用New函数后更改Name和Votes变量吗?
    • 好简单的例子。

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

    假设您有以下结构,默认为2
    标签default0和default1。

    1
    2
    3
    4
    type A struct {
       I int    `default0:"3" default1:"42"`
       S string `default0:"Some String..." default1:"Some Other String..."`
    }

    现在可以设置默认值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func main() {

    ptr := &A{}

    Set(ptr,"default0")
    fmt.Printf("ptr.I=%d ptr.S=%s
    ", ptr.I, ptr.S)
    // ptr.I=3 ptr.S=Some String...

    Set(ptr,"default1")
    fmt.Printf("ptr.I=%d ptr.S=%s
    ", ptr.I, ptr.S)
    // ptr.I=42 ptr.S=Some Other String...
    }

    这是操场上的完整程序。

    如果你对一个更复杂的例子感兴趣,请说
    切片和地图,然后,看看creasty / defaultse


    来自https://golang.org/doc/effective_go.html#composite_literals:

    有时零值不够好,并且需要初始化构造函数,如此示例派生自包os。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        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
    }

    1
    2
    3
    type Config struct {
        AWSRegion                               string `default:"us-west-2"`
    }
    • 这是不正确的。最好的情况是,您可以在该字段上设置标记值,然后使用反射获取其值,但即使这样,语法也不正确(缺少后退标记),您只能为字符串类型设置默认值。如果您对此示例的具体内容有所了解,请添加一个链接以参考。