Kan [] string niet converteren naar []-interface {}

Ik ben het schrijven van een code, en ik heb het nodig om de argumenten op te vangen en door te geven door middel van fmt.Println
(Ik wil het standaard gedrag, om te schrijven argumenten gescheiden door spaties en gevolgd door een nieuwe regel). het duurt echter []interface {}, maar flag.Args()retourneert een []string.
Hier is de code voorbeeld:

package main
import (
    "fmt"
    "flag"
)
func main() {
    flag.Parse()
    fmt.Println(flag.Args()...)
}

Dit keert terug de volgende foutmelding:

./example.go:10: cannot use args (type []string) as type []interface {} in function argument

Is dit een bug? Moet niet fmt.Printlnneem geen reeks? By the way, ik heb ook geprobeerd om dit te doen:

var args = []interface{}(flag.Args())

maar ik krijg de volgende fout:

cannot convert flag.Args() (type []string) to type []interface {}

Is er een “Go” manier om dit?

workaround


1, Autoriteit 100%

Dit is geen bug. fmt.Println()vereist []interface {}type. Dat betekent, moet het een stukje van interface{}waarden en niet “iedere slice” te zijn. Met het oog op het schijfje te zetten, moet u lus over en kopieer elk element.

old := flag.Args()
new := make([]interface{}, len(old))
for i, v := range old {
    new[i] = v
}
fmt.Println(new...)

De reden dat je kunt elk stukje niet gebruiken, is dat conversie tussen een []stringen []interface {}vereist het geheugen lay-out te worden veranderd en gebeurt op tijd binnen. Het omzetten van een soort van een interface{}vereist O (1) tijd. Als ze dit maakte voor lus overbodig, zou de compiler nog steeds nodig om het in te voegen.


2, Autoriteit 10%

In dit geval is een typeconversie overbodig. Gewoon langs de flag.Args()waarde fmt.Println.


Vraag:

Kan niet converteren [] string op []-interface {}

Ik ben het schrijven van een code, en ik heb het nodig om de argumenten te vangen en doorgeven
ze door fmt.Println (ik wil het standaard gedrag, om te schrijven
argumenten gescheiden door spaties en gevolgd door een nieuwe regel).

Hier is de code voorbeeld:

package main
import (
    "fmt"
    "flag"
)
func main() {
    flag.Parse()
    fmt.Println(flag.Args()...)
}

vlag Package

import "flag"

func Args

func Args() []string

Argsgeeft de niet-flag command-line argumenten.


Package FMT

import "fmt"

func Println

func Println(a ...interface{}) (n int, err error)

Printlnformats met behulp van de standaard formaten voor de operanden en
schrijft naar standaarduitvoer. Ruimten altijd toegevoegd tussen operanden
en een nieuwe regel wordt toegevoegd. Het geeft het aantal bytes geschreven en
elke afschrijving fout opgetreden.


In dit geval is een typeconversie overbodig. Gewoon langs de flag.Args()waarde fmt.Println, die reflectie gebruikt om de waarde als type []stringinterpreteren. Pakket reflectwerktuigen run-time reflectie, waardoor een programma om objecten te manipuleren willekeurige types. Bijvoorbeeld,

args.go

package main
import (
    "flag"
    "fmt"
)
func main() {
    flag.Parse()
    fmt.Println(flag.Args())
}

Uitgang:

$ go build args.go
$ ./args arg0 arg1
[arg0 arg1]
$ 

3, Autoriteit 9%

Als het slechts een plakje snaren is die u wilt afdrukken, kunt u conversie vermijden en exact dezelfde uitvoer krijgen door lid te worden van:

package main
import (
    "fmt"
    "flag"
    "strings"
)
func main() {
    flag.Parse()
    s := strings.Join(flag.Args(), " ")
    fmt.Println(s)
}

4

Een andere optie is om het segment gewoon te herhalen:

package main
import "flag"
func main() {
   flag.Parse()
   for _, each := range flag.Args() {
      println(each)
   }
}

Antwoord 5

Ik denk dat het mogelijk is om reflectie te gebruiken, maar ik weet niet of het een goede oplossing is

package main
import (
    "fmt"
    "reflect"
    "strings"
)
type User struct {
    Name string
    Age  byte
}
func main() {
    flag.Parse()
    fmt.Println(String(flag.Args()))
    fmt.Println(String([]string{"hello", "world"}))
    fmt.Println(String([]int{1, 2, 3, 4, 5, 6}))
    u1, u2 := User{Name: "John", Age: 30},
        User{Name: "Not John", Age: 20}
    fmt.Println(String([]User{u1, u2}))
}
func String(v interface{}) string {
    val := reflect.ValueOf(v)
    if val.Kind() == reflect.Array || val.Kind() == reflect.Slice {
        l := val.Len()
        if l == 0 {
            return ""
        }
        if l == 1 {
            return fmt.Sprint(val.Index(0))
        }
        sb := strings.Builder{}
        sb.Grow(l * 4)
        sb.WriteString(fmt.Sprint(val.Index(0)))
        for i := 1; i < l; i++ {
            sb.WriteString(",")
            sb.WriteString(fmt.Sprint(val.Index(i)))
        }
        return sb.String()
    }
    return fmt.Sprintln(v)
}

Uitvoer:

$ go run .\main.go arg1 arg2
arg1,arg2
hello,world
1,2,3,4,5,6
{John 30},{Not John 20}

Antwoord 6

fmt.Printlnneemt variadic parameter

func Println(a …interface{}) (n int, err error)

Het is mogelijk om flag.Args()af te drukken zonder te converteren naar een []interface{}

func main() {
    flag.Parse()
    fmt.Println(flag.Args())
}

Other episodes