Go'nun isteğe bağlı parametreleri olabilir mi? Yoksa aynı ada ve farklı sayıda bağımsız değişkene sahip iki işlev tanımlayabilir miyim?
Go'nun isteğe bağlı parametreleri olabilir mi? Yoksa aynı ada ve farklı sayıda bağımsız değişkene sahip iki işlev tanımlayabilir miyim?
Yanıtlar:
Go'nun isteğe bağlı parametreleri yoktur veya yöntem aşırı yüklenmesini desteklemez :
Tür eşleştirme yapması gerekmiyorsa yöntem dağıtımı basitleştirilir. Diğer dillerle ilgili deneyimler bize, aynı ada ancak farklı imzalara sahip çeşitli yöntemlere sahip olmanın bazen yararlı olduğunu ancak pratikte kafa karıştırıcı ve kırılgan olabileceğini söyledi. Yalnızca isimle eşleştirmek ve türlerde tutarlılık gerektirmek Go'nun tür sisteminde basitleştirici bir karardı.
make
, sonra özel bir durum? Yoksa gerçekten bir işlev olarak uygulanmadı mı…
make
bir dil yapısıdır ve yukarıda belirtilen kurallar geçerli değildir. Bu ilgili soruya bakın .
range
make
bu anlamda aynı durumdur
İsteğe bağlı parametreler gibi bir şey elde etmenin güzel bir yolu varyasyon değişkenlerini kullanmaktır. İşlev aslında belirttiğiniz türden bir dilim alır.
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
params
bir dilim ints
Parametreleri içeren bir yapı kullanabilirsiniz:
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})
İsteğe bağlı olarak çok sayıda isteğe bağlı parametre için, hoş bir deyim İşlevsel seçenekleri kullanmaktır .
Türünüz için Foobar
, önce yalnızca bir kurucu yazın:
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
}
burada her seçenek Foobar'ı değiştiren bir işlevdir. Ardından, kullanıcınızın standart seçenekleri kullanması veya oluşturması için uygun yollar sağlayın, örneğin:
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
}
}
Kısaca, seçeneklerin türüne bir ad verebilirsiniz ( Oyun Alanı ):
type OptionFoobar func(*Foobar) error
Zorunlu parametrelere ihtiyacınız varsa, varyasyondan önce kurucunun ilk argümanları olarak ekleyin options
.
İşlevsel seçenekler deyiminin temel faydaları şunlardır:
Bu teknik Rob Pike tarafından üretildi ve Dave Cheney tarafından da gösterildi .
func()
bu yaklaşımın etrafında bükmektense , özellikleri gerekirse olması gereken bir değerler yapısını iletmeyi tercih ederim . Yankı kütüphanesinde olduğu gibi bu yaklaşımı kullanmak zorunda kaldığımda, beynimin soyutlamaların tavşan deliğine sıkıştığını görüyorum. #fwiw
Go'da isteğe bağlı parametreler veya işlev aşırı yüklemesi desteklenmez. Go değişken sayıda parametreyi destekler: Bağımsız değişkenleri ... parametrelerine iletme
Hayır - hiçbiri. Başına C ++ programcıları için Go docs,
Go, işlev aşırı yüklenmesini desteklemez ve kullanıcı tanımlı işleçleri desteklemez.
İsteğe bağlı parametrelerin desteklenmediği gibi eşit derecede açık bir ifade bulamıyorum, ancak desteklenmiyor.
Bunu, aşağıdakine benzer bir fonkta oldukça güzel bir şekilde kapsülleyebilirsiniz.
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
}
Bu örnekte, istemde varsayılan olarak iki nokta üst üste ve önünde bir boşluk vardır. . .
:
. . . ancak bilgi istemi işlevine bir parametre sağlayarak bunu geçersiz kılabilirsiniz.
prompt("Input here -> ")
Bu, aşağıdaki gibi bir istemle sonuçlanacaktır.
Input here ->
Sonunda params ve varyantik argümanların bir yapısını kullandım. Bu şekilde, birkaç servis tarafından tüketilen mevcut arayüzü değiştirmek zorunda kalmadım ve servisim gerektiğinde ek parametreler geçebildi. Golang oyun alanındaki örnek kod: https://play.golang.org/p/G668FA97Nu
Biraz geç kaldım, ancak akıcı arayüzden hoşlanıyorsanız ayarlayıcılarınızı aşağıdaki gibi zincirleme çağrılar için tasarlayabilirsiniz:
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
}
Ve sonra şöyle deyin:
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)
}
}
Bu, @Ripounet yanıtında sunulan İşlevsel seçenekler deyimine benzer ve aynı avantajlardan yararlanır, ancak bazı dezavantajları vardır:
err
değişkeni bildirip sıfırlamak için bir satır harcamanız gerekir.Bununla birlikte, olası küçük bir avantaj vardır, bu tür işlev çağrıları derleyicinin satır içi için daha kolay olmalıdır, ancak gerçekten bir uzman değilim.
Bir harita ile rastgele adlandırılmış parametreleri iletebilirsiniz.
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})
}
Başka bir olasılık, geçerli olup olmadığını belirtmek için alanlı bir yapı kullanmak olacaktır. NullString gibi sql'den null türleri uygundur. Kendi türünüzü tanımlamak güzel, ancak özel bir veri türüne ihtiyacınız varsa her zaman aynı kalıbı takip edebilirsiniz. Ben isteğe bağlı-ness fonksiyon tanımından açık olduğunu ve minimum ekstra kod veya çaba olduğunu düşünüyorum.
Örnek olarak:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}