英文:
How to deal with long parameter lists in `New(...` functions
问题
假设我有一个名为MyStruct
的本地化结构体,其具有以下结构:
struct MyStruct {
myField1 string
myField2 string
myField3 string
...
myFieldN string
}
还有一个用于为外部调用者实例化新的MyStruct
的函数:
func NewMyStruct(myField1, myField2, myField3, ..., myFieldN string) MyStruct {
return MyStruct{
myField1: myField1,
myField2: myField2,
myField3: myField3,
...
myFieldN: myFieldN,
}
}
问题:如果结构体中的字段太多,导致NewMyStruct(...
函数的参数过多,我该如何处理这种情况? 有没有什么最佳实践来减轻这个问题?目前,我的代码库中有几个类似这样的函数:
func NewSuperStruct(myField1, myField2, myField3, myField4, myField5, myField6, myField7, myField8, myField9, myField10, myField11, myField12, myField13, myField14, myField15, myField16, myField17, myField18, myField19, myField20, myField21, myField22) ...
但并不是说这些结构体本身是无意义的,也就是说这些属性/字段不属于它们,在我的应用程序中它们是有意义的,只是结构体太大了,仅此而已。
英文:
Say I have a localised struct called MyStruct
with the following body:
struct MyStruct {
myField1 string
myField2 string
myField3 string
...
myFieldN string
}
And a function which instantiates new MyStruct
s for external callers:
func NewMyStruct(myField1, myField2, myField3, ..., myFieldN string) MyStruct {
return MyStruct{
myField1: myField1,
myField2: myField2,
myField3: myField3,
...
myFieldN: myFieldN,
}
}
Question: How would I best deal with the scenario of there being just too many fields within the struct resulting in a NewMyStruct(...
function with way too many parameters? Is there any best practice to mitigate this issue? As of now, I have several functions like this in my codebase:
func NewSuperStruct(myField1, myField2, myField3, myField4, myField5, myField6, myField7, myField8, myField9, myField10, myField11, myField12, myField13, myField14, myField15, myField16, myField17, myField18, myField19, myField20, myField21, myField22) ...
But it's not necessarily that the structs themselves are nonsensical in the sense that the properties/fields don't belong within, in my application they do make sense, the structs are just too large, that's all.
答案1
得分: 4
我会说,不要使用New
函数:
type MyStruct struct {
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,
}
}
英文:
I'd say just don't have the New
func:
struct MyStruct {
myField1 string
myField2 string
myField3 string
}
val := MyStruct{
myField1: "one",
myField2: "two",
myField3: "three",
}
If unexported fields need to be set from another package, use some kind of options or config:
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,
}
}
答案2
得分: 3
个人而言(显然取决于结构的目标),我非常喜欢函数选项:
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"),
...
)
这有几个好处:
- 调用者不需要担心顺序问题
- 通过字段名显式传递值,这意味着你不会混淆Field1和Field2
- 你可以在调用者不传递
WithField1
的情况下,为MyStruct
传递不同的默认值 - 添加更多字段不会导致必须更新
New
的所有调用者
英文:
Personally (obviously depending on the goal of the struct) I am a big fan of functional options:
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
}
which can be used as follows:
New(
WithField1("someString"),
...
)
This has a couple of benefits:
- Callers of new do not need to worry about the order
- Passing values is explicit with field name, which means you won't mix up Field1 & Field2
- You have the ability to pass different defaults to
MyStruct
in case callers don't passWithField1
- Adding more fields doesn't lead to having to update all callers of
New
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论