英文:
Equivalent of optional parameters in Go
问题
我正在将一个客户端从Python迁移到一个API。原始实现使用可选参数,如下所示:
def createIntAttribute(attr_name, default_value=None, is_array=False)
这将在数据库中创建一个整数属性,可以选择是否使用默认值,例如:
createIntAttribute("numUsers") # 没有默认属性
createIntAttribute("numUsers", 0) # 默认属性为0
在Go中如何实现这个功能呢?
我考虑了一些方法:
-
使用int类型
无法确定用户是想避免创建默认值还是想创建默认值为0的属性。 -
使用指针
defaultValue *int
需要在每次使用时加上&
,并且不支持字面量。 -
使用参数结构体
int的默认值是0,所以和第一种方法一样存在同样的问题。 -
使用带有value和isSet属性的结构体封装可选参数
需要为每种类型的变量创建一个结构体。这可能可以使用泛型来实现,但要求Go版本大于1.18。使用方式为mypackage.NewOptionalStringArray([]string{"hello", "world"})
。 -
使用可变参数函数
func createIntAttribute(name string, optionals ...interface{})
默认情况下没有类型检查。自动完成不会显示变量的名称和类型;使用VS Code的单独参数会在我输入时显示参数的名称和类型。
哪种方法是最好的实现方式呢?
英文:
I am porting a client to an API from python. The original implementation uses optional parameters as
def createIntAttribute(attr_name, default_value=None, is_array=False)
which create an integer attribute on database with or without a default value as in:
createIntAttribute("numUsers") # No default attribute
createIntAttribute("numUsers", 0) # Default attribute of 0
How can this be implemented in Go?
Some approaches I have considered are:
- Using int as type
There's no way to know if user wanted to avoid creating a default value or wanted to create a default of 0 - Using a pointer
defaultValue *int
Needs&
on every use and doesn't support literals - Using a struct for parameters
The default value for int is 0 so same problem as first approach - Using a struct with value and isSet attributes to enclose optional parameters
Needs a struct for each type of variable. This can probably use generics but adds a requirement of go version > 1.18
usage ismypackage.NewOptionalStringArray([]string{"hello", "world"})
- Using variadic function
func createIntAttribute(name string, optionals ...interface{})
No typechecking by default
Autocomplete doesn't show name and type of variable; using individual argument with vs code shows the name of argument and its type as I am typing them
What would be the best way to implement this?
答案1
得分: 4
一种方法是使用Functional Options Pattern。请参考下面的示例代码:
package main
import (
"log"
)
type options struct {
hasDefault bool
defaultValue int
}
type option func(*options)
func withDefault(value int) option {
return func(o *options) {
o.hasDefault = true
o.defaultValue = value
}
}
func createIntAttribute(name string, setters ...option) {
o := &options{}
for _, setter := range setters {
setter(o)
}
log.Println(name, o)
}
func main() {
createIntAttribute("test1")
createIntAttribute("test1", withDefault(10))
}
这种方法可以更加用户友好(也许),当作为方法链实现时:
package main
import (
"log"
)
type createIntAttributeParams struct {
name string
hasDefault bool
defaultValue int
}
// 必需的参数在这里
func createIntAttribute(name string) *createIntAttributeParams {
return &createIntAttributeParams{
name: name,
}
}
// 可选参数
func (p *createIntAttributeParams) withDefault(value int) *createIntAttributeParams {
p.hasDefault = true
p.defaultValue = value
return p
}
// 其他 with* 函数用于设置更多可选参数
// 执行
func (p *createIntAttributeParams) do() {
log.Println(*p)
}
func main() {
createIntAttribute("test1").do()
createIntAttribute("test1").withDefault(10).do()
}
英文:
One approach is to use the Functional Options Pattern. See the demo below:
package main
import (
"log"
)
type options struct {
hasDefault bool
defaultValue int
}
type option func(*options)
func withDefault(value int) option {
return func(o *options) {
o.hasDefault = true
o.defaultValue = value
}
}
func createIntAttribute(name string, setters ...option) {
o := &options{}
for _, setter := range setters {
setter(o)
}
log.Println(name, o)
}
func main() {
createIntAttribute("test1")
createIntAttribute("test1", withDefault(10))
}
This approach can be more user friendly (maybe) when implemented as method chain:
package main
import (
"log"
)
type createIntAttributeParams struct {
name string
hasDefault bool
defaultValue int
}
// mandatory parameters here
func createIntAttribute(name string) *createIntAttributeParams {
return &createIntAttributeParams{
name: name,
}
}
// optional parameter
func (p *createIntAttributeParams) withDefault(value int) *createIntAttributeParams {
p.hasDefault = true
p.defaultValue = value
return p
}
// other with* functions to set more optional parameters
// execute
func (p *createIntAttributeParams) do() {
log.Println(*p)
}
func main() {
createIntAttribute("test1").do()
createIntAttribute("test1").withDefault(10).do()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论