Domanda
Può Andare avere parametri opzionali? O posso solo definire due funzioni con lo stesso nome e un diverso numero di argomenti?
Soluzione
Go non ha parametri opzionali né supporta il metodo sovraccarico :
Metodo spedizione è semplificata se non ha bisogno di fare il tipo di corrispondenza come bene. L'esperienza con altre lingue ci ha detto che avere una varietà di metodi con lo stesso nome, ma firme diverse era tanto in tanto utile ma che potrebbe anche essere confusa e fragile nella pratica. Corrispondenza solo per nome e che richiedono coerenza nei tipi era un importante semplificando decisione tipo di Go sistema.
Altri suggerimenti
Un bel modo per ottenere qualcosa come parametri opzionali è quello di utilizzare args variadic. La funzione riceve effettivamente una fetta di qualunque tipo specificato.
func foo(params ...int) {
fmt.Println(len(params))
}
func main() {
foo()
foo(1)
foo(1,2,3)
}
È possibile utilizzare una struttura che comprende i parametri:
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})
Per arbitraria, numero potenzialmente elevato di parametri opzionali, un bel linguaggio è quello di utilizzare Opzioni funzionali .
Per il tipo di Foobar
, primo scrivere solo un costruttore:
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
}
dove ogni opzione è una funzione che muta la Foobar. Quindi fornire modi convenienti per l'utente di utilizzare o creare opzioni standard, ad esempio:
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
}
}
Per brevità, si può dare un nome al tipo di opzioni ( Playground ):
type OptionFoobar func(*Foobar) error
Se avete bisogno di parametri obbligatori, aggiungerli come primi argomenti del costruttore prima della options
variadic.
I principali vantaggi del Opzioni funzionali idioma sono:
- la tua API può crescere nel tempo senza rompere il codice esistente, perché la firma constuctor rimane lo stesso quando sono necessarie nuove opzioni.
- permette il caso d'uso di default di essere la sua più semplice: nessun argomento a tutti
- fornisce un controllo preciso l'inizializzazione di valori complessi.
Questa tecnica è stato coniato da Rob Pike e anche dimostrato da Dave Cheney .
Né parametri opzionali né l'overloading di funzioni sono supportate in Go. Go supporta un numero variabile di parametri: Passaggio di argomenti a ... parametri
No - nessuno dei due. Per il Andare per programmatori C ++ docs,
Go non supporta la funzione sovraccarichi e non supporta utenti operatori definiti.
Non riesco a trovare una dichiarazione altrettanto chiaro che i parametri opzionali non sono supportati, ma non sono supportate sia.
È possibile incapsulare questo abbastanza bene in un func simile a ciò che è al di sotto.
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
}
In questo esempio, il prompt di default ha due punti e uno spazio di fronte ad essa. . .
:
. . . tuttavia è possibile ignorare che fornendo un parametro alla funzione pronta.
prompt("Input here -> ")
Questo si tradurrà in un prompt come qui di seguito.
Input here ->
Ho finito per usare una combinazione di una struttura di params e args variadic. In questo modo, io non ha dovuto modificare l'interfaccia esistente che è stato consumato da diversi servizi e il mio servizio è stato in grado di passare params aggiuntivi, se necessario. codice di esempio in un parco giochi golang: https://play.golang.org/p/G668FA97Nu
Io sono un po 'in ritardo, ma se vi piace l'interfaccia fluente si potrebbe progettare le setter per le chiamate concatenate in questo modo:
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
}
E poi chiamare in questo modo:
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)
}
}
Questo è simile alla Opzioni funzionali idioma presentato in risposta @Ripounet e gode degli stessi benefici, ma ha alcuni svantaggi:
- Se si verifica un errore non interrompe immediatamente, in tal modo, sarebbe un po 'meno efficiente se vi aspettate il vostro costruttore di segnalare gli errori spesso.
- Dovrete passare una linea di dichiarare una variabile
err
e l'azzeramento di esso.
V'è, tuttavia, un eventuale piccolo vantaggio, questo tipo di chiamate di funzione dovrebbe essere più facile per il compilatore inline ma io non sono davvero uno specialista.
Vai linguaggio non supporta overloading dei metodi, ma è possibile utilizzare args variadic proprio come parametri opzionali, inoltre è possibile usare l'interfaccia {} come parametro, ma non è una buona scelta.
È possibile passare arbitrari parametri denominati con una mappa.
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})
}