program tip

[] 문자열을 [] 인터페이스 {}로 변환 할 수 없습니다.

radiobox 2020. 10. 8. 07:52
반응형

[] 문자열을 [] 인터페이스 {}로 변환 할 수 없습니다.


나는 몇 가지 코드를 작성하고 있으며 인수를 잡아서 전달하는 데 필요합니다 fmt.Println
(기본 동작, 공백으로 구분 된 인수를 작성하고 그 뒤에 줄 바꿈이 이어짐). 그러나이 소요 []interface {}되지만 flag.Args()다시 발생 []string.
다음은 코드 예입니다.

package main

import (
    "fmt"
    "flag"
)

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

다음 오류가 반환됩니다.

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

이것은 버그입니까? fmt.Println가지고 있는 배열을? 그건 그렇고, 나는 또한 이것을 시도했습니다.

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

하지만 다음과 같은 오류가 발생합니다.

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

이 문제를 해결할 수있는 "이동"방법이 있습니까?


이것은 버그가 아닙니다. 유형이 fmt.Println()필요합니다 []interface{}. 즉, interface{}"모든 조각"이 아닌 값 조각이어야합니다 . 슬라이스를 변환하려면 각 요소를 반복하고 복사해야합니다.

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

슬라이스를 사용할 수없는 이유는 a []string와 a 간의 변환 []interface{}이 메모리 레이아웃을 변경해야하고 O (n) 시간에 발생하기 때문입니다. 형식을로 변환 interface{}하려면 O (1) 시간이 필요합니다. for 루프를 불필요하게 만들었더라도 컴파일러는이를 삽입해야합니다.


이 경우 형식 변환이 필요하지 않습니다. flag.Args()값을에 전달하기 만하면 됩니다 fmt.Println.


질문:

[] 문자열을 [] 인터페이스 {}로 변환 할 수 없습니다.

몇 가지 코드를 작성 중이며 인수를 잡아서 fmt.Println을 통해 전달하는 데 필요합니다 (기본 동작, 공백으로 구분 된 인수를 작성하고 그 뒤에 줄 바꿈이 이어짐).

다음은 코드 예입니다.

package main

import (
    "fmt"
    "flag"
)

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

패키지 플래그

import "flag"

func Args

func Args() []string

Args 플래그가 아닌 명령 줄 인수를 반환합니다.


패키지 fmt

import "fmt"

func Println

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

Println피연산자에 대한 기본 형식을 사용하여 형식을 지정하고 표준 출력에 기록합니다. 피연산자 사이에는 항상 공백이 추가되고 개행 문자가 추가됩니다. 쓰여진 바이트 수와 발생한 쓰기 오류를 반환합니다.


이 경우 형식 변환이 필요하지 않습니다. flag.Args()값을에 전달하면 fmt.Println리플렉션을 사용하여 값을 유형으로 해석합니다 []string. 패키지 reflect는 런타임 리플렉션을 구현하여 프로그램이 임의 유형의 개체를 조작 할 수 있도록합니다. 예를 들면

args.go:

package main

import (
    "flag"
    "fmt"
)

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

산출:

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

인쇄하려는 문자열 조각 만 있으면 변환을 피하고 조인하여 정확히 동일한 출력을 얻을 수 있습니다.

package main

import (
    "fmt"
    "flag"
    "strings"
)

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

Go에서 함수는 함수 정의의 매개 변수 목록에 지정된 유형의 인수 만받을 수 있습니다. 가변 매개 변수 언어 기능은이를 약간 복잡하게 만들지 만 잘 정의 된 규칙을 따릅니다.

에 대한 함수 서명 fmt.Println은 다음과 같습니다.

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

언어 specifiction ,

함수 시그니처의 최종 수신 매개 변수에는 ... 접두사가 붙은 유형이있을 수 있습니다. 이러한 매개 변수가있는 함수를 가변이라고하며 해당 매개 변수에 대해 0 개 이상의 인수를 사용하여 호출 할 수 있습니다.

This means you can pass Println a list of arguments of interface{} type. Since all types implement the empty interface, you can pass a list of arguments of any type, which is how you're able to call Println(1, "one", true), for example, without error. See the "Passing arguments to ... parameters" section of the language specification:

the value passed is a new slice of type []T with a new underlying array whose successive elements are the actual arguments, which all must be assignable to T.

The part that's giving you trouble is right after that in the specification:

If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.

flag.Args() is type []string. Since T in Println is interface{}, []T is []interface{}. So the question comes down to whether a string slice value is assignable to a variable of interface slice type. You can easily test that in your go code by attempting an assignment, for example:

s := []string{}
var i []interface{}
i = s

If you attempt such an assignment, the compiler will output this error message:

cannot use s (type []string) as type []interface {} in assignment

And that's why you can't use the ellipsis after a string slice as an argument to fmt.Println. It's not a bug, it's working as intended.

There are still lots of ways you can print flag.Args() with Println, such as

fmt.Println(flag.Args())

(which will output as [elem0 elem1 ...], per fmt package documentation)

or

fmt.Println(strings.Join(flag.Args(), ` `)

(which will output the string slice elements, each separated by a single space) using the Join function in the strings package with a string separator, for example.


I think it's possible using reflection, but I don't know if it's a good solution

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

Output:

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

fmt.Println takes variadic parameter

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

Its possible to print flag.Args() without converting into []interface{}

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

참고URL : https://stackoverflow.com/questions/12990338/cannot-convert-string-to-interface

반응형