Wartość domyślna w metodzie Go

103

Czy istnieje sposób na określenie wartości domyślnej w funkcji Go? Próbuję znaleźć to w dokumentacji, ale nie mogę znaleźć niczego, co by wskazywało, że jest to w ogóle możliwe.

func SaySomething(i string = "Hello")(string){
...
}
Denniss
źródło

Odpowiedzi:

129

NIE, ale są inne opcje implementacji wartości domyślnej. Jest kilka dobrych postów na ten temat, ale oto kilka konkretnych przykładów.


** Opcja 1: ** Dzwoniący decyduje się na użycie wartości domyślnych
// Both parameters are optional, use empty string for default value
func Concat1(a string, b int) string {
  if a == "" {
    a = "default-a"
  }
  if b == 0 {
    b = 5
  }

  return fmt.Sprintf("%s%d", a, b)
}

** Opcja 2: ** Pojedynczy opcjonalny parametr na końcu
// a is required, b is optional.
// Only the first value in b_optional will be used.
func Concat2(a string, b_optional ...int) string {
  b := 5
  if len(b_optional) > 0 {
    b = b_optional[0]
  }

  return fmt.Sprintf("%s%d", a, b)
}

** Opcja 3: ** Struktura konfiguracji
// A declarative default value syntax
// Empty values will be replaced with defaults
type Parameters struct {
  A string `default:"default-a"` // this only works with strings
  B string // default is 5
}

func Concat3(prm Parameters) string {
  typ := reflect.TypeOf(prm)

  if prm.A == "" {
    f, _ := typ.FieldByName("A")
    prm.A = f.Tag.Get("default")
  }

  if prm.B == 0 {
    prm.B = 5
  }

  return fmt.Sprintf("%s%d", prm.A, prm.B)
}

** Opcja 4: ** Pełna analiza zmiennych argumentów (styl javascript)
func Concat4(args ...interface{}) string {
  a := "default-a"
  b := 5

  for _, arg := range args {
    switch t := arg.(type) {
      case string:
        a = t
      case int:
        b = t
      default:
        panic("Unknown argument")
    }
  }

  return fmt.Sprintf("%s%d", a, b)
}
dyrektor szkoły
źródło
99
Co za ból. Chciałbym, żeby tak było: func Concat1(a string = 'foo', b int = 10) string {jak w większości innych współczesnych języków ... To zredukowałoby dowolny z podanych przykładów do jednej linii kodu.
Rotareti
Czy mamy możliwość napisania dwóch różnych funkcji i pozostawienie wywołującemu wyraźne określenie, czego oczekują?
ProgramCpp
@ProgramCpp nie, golang nie pozwala na przeciążanie funkcji Czy język Go ma przeciążenie funkcji / metod?
Vusal
11

Nie, nie ma możliwości określenia wartości domyślnych. Wierzę, że robi się to celowo, aby zwiększyć czytelność, kosztem trochę więcej czasu (i miejmy nadzieję, przemyślenia) po stronie autora.

Myślę, że właściwym podejściem do posiadania „wartości domyślnej” jest posiadanie nowej funkcji, która zapewnia tę domyślną funkcję bardziej ogólną. Mając to, twój kod staje się jaśniejszy w twoim zamiarze. Na przykład:

func SaySomething(say string) {
    // All the complicated bits involved in saying something
}

func SayHello() {
    SaySomething("Hello")
}

Z niewielkim wysiłkiem stworzyłem funkcję, która robi zwykłą rzecz i ponownie użyłem funkcji ogólnej. Możesz to zobaczyć w wielu bibliotekach, fmt.Printlnna przykład po prostu dodaje nowy wiersz do tego fmt.Print, co by zrobił w przeciwnym razie. Jednak czytając czyjś kod, jest jasne, co zamierza zrobić za pomocą funkcji, którą wywołuje. Przy wartościach domyślnych nie będę wiedział, co ma się stać, bez przejścia do funkcji, aby odnieść się do wartości domyślnej.

Dave
źródło
Podoba mi się i zgadzam się z tą odpowiedzią, ale do cholery nadal chciałbym, żeby przynajmniej mieli tępy, ale idiomatyczny sposób, aby to zrobić.
Sam Gomena
15
Argument „po prostu dodaj kolejną funkcję” może spowodować eksplozję metod wymaganych do radzenia sobie z wieloma permutacjami, wymaga podjęcia decyzji o znaczących, wykrywalnych i zapamiętanych nazwach dla tych metod oraz zwiększa obciążenie uczenia się pakietów, które używają więcej metod w porównaniu z , mniej. #jmtcw
MikeSchinkel