Goにオプションのパラメーターを指定できますか?または、同じ名前で引数の数が異なる2つの関数を定義できますか?
Goにオプションのパラメーターを指定できますか?または、同じ名前で引数の数が異なる2つの関数を定義できますか?
回答:
Goにはオプションのパラメーターがなく、メソッドのオーバーロードもサポートされていません。
タイプマッチングも必要としない場合、メソッドディスパッチは簡略化されます。他の言語を使用した経験から、同じ名前でシグネチャが異なるさまざまなメソッドを使用すると便利な場合がありますが、実際には混乱しやすく、壊れやすいこともあります。名前のみで照合し、型の一貫性を要求することは、Goの型システムにおける主要な簡素化の決定でした。
make
、その後、特殊なケース?それとも、実際には関数として実装されていませんか
make
は言語構成要素であり、上記のルールは適用されません。この関連質問を参照してください。
range
make
その意味ではと同じケースです
オプションのパラメーターのようなものを実現する良い方法は、可変個引数を使用することです。関数は実際に、指定したタイプのスライスを受け取ります。
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
params
は、intのスライスです
パラメータを含む構造体を使用できます:
type Params struct {
a, b, c int
}
func doIt(p Params) int {
return p.a + p.b + p.c
}
// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})
任意の、場合によっては多数のオプションパラメータの場合、便利なイディオムは、機能オプションを使用することです。
タイプにはFoobar
、最初にコンストラクタを1つだけ記述します。
func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
fb := &Foobar{}
// ... (write initializations with default values)...
for _, op := range options{
err := op(fb)
if err != nil {
return nil, err
}
}
return fb, nil
}
各オプションは、Foobarを変更する関数です。次に、ユーザーが標準オプションを使用または作成するための便利な方法を提供します。次に例を示します。
func OptionReadonlyFlag(fb *Foobar) error {
fb.mutable = false
return nil
}
func OptionTemperature(t Celsius) func(*Foobar) error {
return func(fb *Foobar) error {
fb.temperature = t
return nil
}
}
簡潔にするために、オプションのタイプに名前を付けることができます(Playground):
type OptionFoobar func(*Foobar) error
必須パラメーターが必要な場合は、可変引数の前にコンストラクターの最初の引数として追加しますoptions
。
機能オプションイディオムの主な利点は次のとおりです。
func()
、必要に応じてsにすることもできますが、このアプローチでは頭が曲がります。Echoライブラリーなどでこのアプローチを使用しなければならないときはいつでも、抽象化のうさぎの穴に頭が悩まされています。#fwiw
Goでは、オプションのパラメーターも関数のオーバーロードもサポートされていません。Goは可変数のパラメーターをサポートしています:引数を...パラメーターに渡します
いいえ、どちらでもありません。パーC ++プログラマのために行くドキュメント、
Goは関数のオーバーロードをサポートしておらず、ユーザー定義の演算子もサポートしていません。
オプションのパラメーターがサポートされていないという同様に明確なステートメントを見つけることはできませんが、それらもサポートされていません。
これを以下のようなfuncに非常にうまくカプセル化できます。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Println(prompt())
}
func prompt(params ...string) string {
prompt := ": "
if len(params) > 0 {
prompt = params[0]
}
reader := bufio.NewReader(os.Stdin)
fmt.Print(prompt)
text, _ := reader.ReadString('\n')
return text
}
この例では、プロンプトにはデフォルトでコロンとその前にスペースがあります。。。
:
。。。ただし、プロンプト関数にパラメーターを指定することで、これをオーバーライドできます。
prompt("Input here -> ")
これにより、以下のようなプロンプトが表示されます。
Input here ->
結局、paramsとvariadic argsの構造の組み合わせを使用してしまいました。このようにして、いくつかのサービスによって消費される既存のインターフェースを変更する必要がなくなり、サービスは必要に応じて追加のパラメーターを渡すことができました。golang playgroundのサンプルコード:https : //play.golang.org/p/G668FA97Nu
私は少し遅れますが、流暢なインターフェースが好きな場合は、次のように連鎖呼び出し用のセッターを設計できます。
type myType struct {
s string
a, b int
}
func New(s string, err *error) *myType {
if s == "" {
*err = errors.New(
"Mandatory argument `s` must not be empty!")
}
return &myType{s: s}
}
func (this *myType) setA (a int, err *error) *myType {
if *err == nil {
if a == 42 {
*err = errors.New("42 is not the answer!")
} else {
this.a = a
}
}
return this
}
func (this *myType) setB (b int, _ *error) *myType {
this.b = b
return this
}
そして、次のように呼び出します。
func main() {
var err error = nil
instance :=
New("hello", &err).
setA(1, &err).
setB(2, &err)
if err != nil {
fmt.Println("Failed: ", err)
} else {
fmt.Println(instance)
}
}
これは、@ Ripounetの回答で提示された機能オプションイディオムに似ており、同じ利点を享受しますが、いくつかの欠点があります。
err
変数を宣言してゼロにする行を費やす必要があります。ただし、小さな利点もある可能性があります。このタイプの関数呼び出しは、コンパイラーがインライン化する方が簡単ですが、私は実際には専門家ではありません。
マップで任意の名前付きパラメーターを渡すことができます。
type varArgs map[string]interface{}
func myFunc(args varArgs) {
arg1 := "default" // optional default value
if val, ok := args["arg1"]; ok {
// value override or other action
arg1 = val.(string) // runtime panic if wrong type
}
arg2 := 123 // optional default value
if val, ok := args["arg2"]; ok {
// value override or other action
arg2 = val.(int) // runtime panic if wrong type
}
fmt.Println(arg1, arg2)
}
func Test_test() {
myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
別の可能性は、有効かどうかを示すフィールドを持つ構造体を使用することです。NullStringなどのSQLのnull型は便利です。独自のタイプを定義する必要がないのは良いことですが、カスタムデータタイプが必要な場合は、常に同じパターンに従うことができます。オプション性は関数定義から明らかで、余分なコードや労力は最小限で済むと思います。
例として:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}