Ich schreibe Code, und ich brauche ihn, um die Argumente fmt.Println
abzufangen und durchzuleiten (ich möchte das Standardverhalten, um durch Leerzeichen getrennte Argumente zu schreiben, gefolgt von einer neuen Zeile). Es dauert []interface {}
jedoch aber flag.Args()
gibt a zurück []string
.
Hier ist das Codebeispiel:
package main
import (
"fmt"
"flag"
)
func main() {
flag.Parse()
fmt.Println(flag.Args()...)
}
Dies gibt den folgenden Fehler zurück:
./example.go:10: cannot use args (type []string) as type []interface {} in function argument
Ist das ein Fehler? Sollte nicht fmt.Println
nehmen jede Array? Übrigens habe ich auch versucht, dies zu tun:
var args = []interface{}(flag.Args())
aber ich bekomme folgenden Fehler:
cannot convert flag.Args() (type []string) to type []interface {}
Gibt es einen "Go" Weg, um dies zu umgehen?
type-conversion
go
cruizh
quelle
quelle
go run test.go some test flags
) herumgespielt , und es schien zu funktionieren, wennflags.Args()...
auf just gewechselt wurdeflag.Args()
(Ausgabe ist[some test flags]
, gefolgt von der neuen Zeile; schien auch mit der Registrierung tatsächlicher Flags zu funktionieren).Antworten:
Dies ist kein Fehler.
fmt.Println()
erfordert einen[]interface{}
Typ. Das heißt, es muss ein Werteschnitt seininterface{}
und nicht "irgendein Teil". Um das Slice zu konvertieren, müssen Sie jedes Element durchlaufen und kopieren.Der Grund, warum Sie kein Slice verwenden können, ist, dass für die Konvertierung zwischen a
[]string
und a[]interface{}
das Speicherlayout geändert werden muss und dies in O (n) -Zeit erfolgt. Das Konvertieren eines Typs in einen Typinterface{}
erfordert O (1) Zeit. Wenn sie diese for-Schleife unnötig machen würden, müsste der Compiler sie trotzdem einfügen.quelle
[]string
, erwartet ainterface{}
. Aninterface{}
hat ein anderes Speicherlayout als a,string
daher ist die Tatsache, dass jedes Element konvertiert werden muss, das Problem.Println
Funktion ändert das Slice und setzt einige Elemente (dies ist nicht der Fall, aber es ist der Fall). Dann kann es jedesinterface{}
in die Scheibe legen , die nurstring
s haben sollte. Was Sie wirklich wollen, ist so etwas wie der Java Generics-PlatzhalterSlice<? extends []interface{}>
, aber das gibt es in Go nicht.new()
,len()
undcopy()
. golang.org/ref/spec#Appending_and_copying_slicesWenn es sich nur um ein Stück Zeichenfolgen handelt, die Sie drucken möchten, können Sie die Konvertierung vermeiden und durch Verbinden genau dieselbe Ausgabe erhalten:
quelle
In diesem Fall ist eine Typkonvertierung nicht erforderlich. Übergeben Sie einfach den
flag.Args()
Wert anfmt.Println
.In diesem Fall ist eine Typkonvertierung nicht erforderlich. Übergeben Sie einfach den
flag.Args()
Wert anfmt.Println
, der den Wert mithilfe der Reflexion als Typ interpretiert[]string
. Das Paketreflect
implementiert die Laufzeitreflexion, sodass ein Programm Objekte mit beliebigen Typen bearbeiten kann. Beispielsweise,args.go
::Ausgabe:
quelle
In Go kann eine Funktion nur Argumente der in der Parameterliste in der Funktionsdefinition angegebenen Typen akzeptieren. Die Sprachfunktion für verschiedene Parameter erschwert dies ein wenig, folgt jedoch genau definierten Regeln.
Die Funktionssignatur für
fmt.Println
lautet:Per der Sprache specific ,
Dies bedeutet, dass Sie
Println
eine Liste von Argumenten vominterface{}
Typ übergeben können. Da alle Typen die leere Schnittstelle implementieren, können Sie eine Liste von Argumenten eines beliebigen Typs übergeben. So können SiePrintln(1, "one", true)
beispielsweise fehlerfrei aufrufen . Siehe den Abschnitt "Übergeben von Argumenten an ... Parameter" der Sprachspezifikation:Der Teil, der Ihnen Probleme bereitet, steht direkt danach in der Spezifikation:
flag.Args()
ist Typ[]string
. DaT
inPrintln
istinterface{}
,[]T
ist[]interface{}
. Es stellt sich also die Frage, ob ein String-Slice-Wert einer Variablen vom Schnittstellen-Slice-Typ zugewiesen werden kann. Sie können dies einfach in Ihrem Go-Code testen, indem Sie eine Zuweisung versuchen, zum Beispiel:Wenn Sie eine solche Zuweisung versuchen, gibt der Compiler die folgende Fehlermeldung aus:
Und deshalb können Sie die Auslassungspunkte nach einem String-Slice nicht als Argument dafür verwenden
fmt.Println
. Es ist kein Fehler, es funktioniert wie beabsichtigt.Es gibt immer noch viele Möglichkeiten , können Sie drucken
flag.Args()
mitPrintln
, wie(wird
[elem0 elem1 ...]
gemäß der Dokumentation des FMT-Pakets ausgegeben )oder
(wodurch die String-Slice-Elemente ausgegeben werden, die jeweils durch ein einzelnes Leerzeichen getrennt sind) Verwenden Sie beispielsweise die Join-Funktion im Strings-Paket mit einem String-Trennzeichen.
quelle
Ich denke, es ist möglich, Reflexion zu verwenden, aber ich weiß nicht, ob es eine gute Lösung ist
Ausgabe:
quelle
fmt.Println
nimmt variadic ParameterEs ist möglich zu drucken,
flag.Args()
ohne in zu konvertieren[]interface{}
quelle
fmt.Println
Die Unterschrift hat sich seit über 6 Jahren nicht geändert (und das war nur eine Paketänderung fürerror
). Selbst wenn dies der Fall wäre, heißt es in der Spezifikation eindeutig "variadisch mit einem endgültigen Parameter p vom Typ ... T". Innerhalb von f entspricht der Typ von p dem Typ [] T. ", sodass dies keine Rolle spielt.fmt.Println(flags.Args()...)
funktioniert immer noch nicht (Sie vermissen die Slice-Erweiterung), hatfmt.Println(flags.Args())
immer funktioniert.flag.Args()
nur diese Zeit als Argument verwendet wurde,fmt.Println
um diese Zeit zurück zu arbeiten. (Es wäre überraschend, wenn es zu diesem Zeitpunkt nicht wäre)