如何处理 `New(...` 函数中的长参数列表

How to deal with long parameter lists in `New(...` functions

假设我有一个名为 MyStruct 的本地化结构,其主体如下:

struct MyStruct {
  myField1 string
  myField2 string
  myField3 string
  ...
  myFieldN string
}

以及一个为外部调用者实例化新 MyStructs 的函数:

func NewMyStruct(myField1, myField2, myField3, ..., myFieldN string) MyStruct {
  return MyStruct{
    myField1: myField1,
    myField2: myField2,
    myField3: myField3,
    ...
    myFieldN: myFieldN,
  }
}

问题:我如何最好地处理结构中有太多字段导致 NewMyStruct(... 函数 way[=26= 的情况] 参数太多? 是否有缓解此问题的最佳做法?截至目前,我的代码库中有几个这样的函数:

func NewSuperStruct(myField1, myField2, myField3, myField4, myField5, myField6, myField7, myField8, myField9, myField10, myField11, myField12, myField13, myField14, myField15, myField16, myField17, myField18, myField19, myField20, myField21, myField22) ...

但在 properties/fields 不属于其中的意义上,结构本身不一定是无意义的,在我的应用程序中它们确实有意义,结构太大了,仅此而已。

就个人而言(显然取决于结构的目标)我是功能选项的忠实粉丝:

type MyStructOpts func(*MyStruct)

func WithField1(field1 string) MyStructOps {
  return func(m *MyStruct) {
    m.myField1 = field1
  }
}

func New(opts ...MyStructOpts) *MyStruct {
  m := MyStruct{
    myField1: "someDefaultIfneeded",
  }

  for _, opt := range opts {
    opt(&m)
  }

  return &m
}

可以如下使用:

New(
  WithField1("someString"),
  ...
)

这有两个好处:

  • new的调用者不用担心顺序
  • 通过字段名称显式传递值,这意味着您不会混淆 Field1 和 Field2
  • 您可以将不同的默认值传递给 MyStruct,以防调用者不传递 WithField1
  • 添加更多字段不会导致必须更新 New
  • 的所有调用方

我会说只是没有 New func:

struct MyStruct {
  myField1 string
  myField2 string
  myField3 string
}

val := MyStruct{
    myField1: "one",
    myField2: "two",
    myField3: "three",
}

如果需要从另一个包设置未导出的字段,请使用某种选项或配置:

type MyStruct struct {
    Exported   string
    unexported string
}

type MyStructOptions struct {
    Exported   string
    Unexported string
}

func NewMyStruct(opts MyStructOptions) *MyStruct {
    return &MyStruct{
        Exported: opts.Exported,
        unexported: opts.Unexported,
    }
}