801 Stimmen

Optionale Parameter in Go?

Kann Go optionale Parameter haben? Oder kann ich einfach zwei Funktionen mit demselben Namen und einer unterschiedlichen Anzahl von Argumenten definieren?

1 Stimmen

In diesem Zusammenhang: So kann man obligatorische Parameter erzwingen, wenn man variadic als optionale Parameter verwendet: Ist es möglich, Kompilierzeit Fehler mit benutzerdefinierten Bibliothek in Golang auslösen?

110 Stimmen

Google hat eine schreckliche Entscheidung getroffen, denn manchmal hat eine Funktion einen 90%igen Anwendungsfall und dann einen 10%igen Anwendungsfall. Das optionale Argument ist für diese 10 % des Anwendungsfalls gedacht. Vernünftige Standardwerte bedeuten weniger Code, weniger Code bedeutet mehr Wartbarkeit.

7 Stimmen

Ich halte den Verzicht auf optionale Parameter für eine gute Entscheidung. Ich habe gesehen, dass optionale Parameter in C++ ziemlich stark missbraucht wurden - 40+ Argumente. Es ist sehr fehleranfällig, die Argumente durchzuzählen und sicherzustellen, dass man das richtige angibt, besonders ohne benannte Parameter. Viel besser ist es, eine Struktur zu verwenden, wie von @deamon erwähnt.

5voto

Sumer Punkte 2192

Go unterstützt nicht optionale Parameter , Standardwerte et Funktionsüberladung aber Sie können einige Tricks anwenden, um das Gleiche zu erreichen.

Teilen Sie ein Beispiel, wo Sie unterschiedliche Anzahl und Typ von Argumenten in einer Funktion haben können. Es ist ein einfacher Code für einfaches Verständnis, den Sie um Fehlerbehandlung und etwas Logik ergänzen müssen.

func student(StudentDetails ...interface{}) (name string, age int, area string) {
    age = 10 //Here Age and area are optional params set to default values
    area = "HillView Singapore"

    for index, val := range StudentDetails {
        switch index {
            case 0: //the first mandatory param
                name, _ = val.(string)
            case 1: // age is optional param
                age, _ = val.(int)
            case 2: //area is optional param
                area, _ = val.(string)
        }
    }
    return
}

func main() {
    fmt.Println(student("Aayansh"))
    fmt.Println(student("Aayansh", 11))
    fmt.Println(student("Aayansh", 15, "Bukit Gombak, Singapore"))
}

16 Stimmen

Igitt, das ist ja furchtbar.

3voto

VinGarcia Punkte 807

Ich bin ein wenig spät dran, aber wenn Sie fließende Schnittstellen mögen, könnten Sie Ihre Setter für verkettete Aufrufe wie diese entwerfen:

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
}

Und dann nennen Sie es so:

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)
  }
}

Dies ist ähnlich wie die Funktionelle Optionen Idiom auf @Ripounet Antwort vorgestellt und genießt die gleichen Vorteile, hat aber einige Nachteile:

  1. Wenn ein Fehler auftritt, wird er nicht sofort abgebrochen, daher wäre es etwas weniger effizient, wenn Sie erwarten, dass Ihr Konstruktor häufig Fehler meldet.
  2. Sie müssen eine Zeile mit der Deklaration eines err und die Variable auf Null setzen.

Es gibt jedoch einen möglichen kleinen Vorteil, diese Art von Funktionsaufrufen sollte für den Compiler einfacher zu inline sein, aber ich bin wirklich kein Spezialist.

1 Stimmen

Dies ist ein Bauherrenmuster

0 Stimmen

Meh. Was passiert, wenn A einen Fehler produziert, aber nicht B, C, D, und A ist Ihnen egal?

0 Stimmen

@ Du könntest die Aufrufe einfach trennen, z.B. zuerst alles bauen, was dich interessiert, dann die Fehler prüfen und dann einstellen, was du nicht prüfen willst. Oder wenn Sie derjenige sind, der den Konstruktor in erster Linie schreibt, können Sie die Fehler einfach intern ignorieren und erhalten keinen *Fehler für die Einstellung von A.

2voto

Adriana Punkte 71

Am Ende habe ich eine Kombination aus einer Struktur von params und variadic args verwendet. Auf diese Weise musste ich die bestehende Schnittstelle, die von mehreren Diensten genutzt wurde, nicht ändern und mein Dienst konnte bei Bedarf zusätzliche Parameter übergeben. Beispielcode im Golang-Spielplatz: https://play.golang.org/p/G668FA97Nu

0voto

user2133814 Punkte 2159

Eine andere Möglichkeit wäre die Verwendung einer Struktur mit einem Feld, das angibt, ob sie gültig ist. Die Null-Typen aus Sql wie z.B. NullString sind praktisch. Es ist schön, wenn man nicht seinen eigenen Typ definieren muss, aber falls man einen benutzerdefinierten Datentyp benötigt, kann man immer dem gleichen Muster folgen. Ich denke, die Optionalität ist aus der Funktionsdefinition ersichtlich, und es gibt nur minimalen zusätzlichen Code oder Aufwand.

Ein Beispiel:

func Foo(bar string, baz sql.NullString){
  if !baz.Valid {
        baz.String = "defaultValue"
  }
  // the rest of the implementation
}

0 Stimmen

Dies ist nicht der Punkt der Frage, das Problem bleibt immer noch, wie Sie noch brauchen, um Funktion mit nil/Standard-Struktur als zweiten Parameter aufrufen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X