Equivalent of optional parameters in Go

huangapple go评论63阅读模式
英文:

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 is mypackage.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()
}

huangapple
  • 本文由 发表于 2023年4月23日 09:50:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76082755.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定