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

나는 몇 가지 코드를 작성하고 있으며 인수를 잡아서 전달하는 데 필요합니다 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 루프를 불필요하게 만들었더라도 컴파일러는이를 삽입해야합니다.


답변

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

package main

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

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


답변

이 경우 형식 변환이 필요하지 않습니다. 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]
$


답변

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

의 함수 서명 fmt.Println은 다음과 같습니다.

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

언어 specifiction ,

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

Println, interface{}유형 의 인수 목록을 전달할 수 있습니다 . 모든 유형이 빈 인터페이스를 구현하므로 모든 유형의 인수 목록을 전달할 수 있습니다 Println(1, "one", true). 예를 들어 오류없이 를 호출 할 수 있습니다. 언어 사양의 “… 매개 변수에 인수 전달”섹션 을 참조하십시오 .

전달 된 값은 연속 요소가 실제 인수 인 새 기본 배열이있는 [] T 유형의 새 슬라이스이며, 모두 T에 할당 할 수 있어야합니다.

문제를 일으키는 부분은 사양에서 바로 그 직후입니다.

마지막 인수가 슬라이스 유형 [] T에 할당 될 수있는 경우 인수 다음에 …가 오면 … T 매개 변수의 값으로 변경되지 않고 전달 될 수 있습니다.이 경우 새 슬라이스가 작성되지 않습니다.

flag.Args()유형 []string입니다. 이후 T에이 Println이다 interface{}, []T입니다 []interface{}. 따라서 문제는 문자열 슬라이스 값을 인터페이스 슬라이스 유형의 변수에 할당 할 수 있는지 여부입니다. 다음과 같이 할당을 시도하여 go 코드에서 쉽게 테스트 할 수 있습니다.

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

이러한 할당을 시도하면 컴파일러는 다음 오류 메시지를 출력합니다.

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

이것이 바로 문자열 조각 뒤에있는 줄임표를에 대한 인수로 사용할 수없는 이유 fmt.Println입니다. 버그가 아니라 의도 한대로 작동합니다.

인쇄 할 수있는 방법의 여전히 많이 있습니다 flag.Args()Println같은이,

fmt.Println(flag.Args())

( fmt 패키지 문서에[elem0 elem1 ...] 따라 로 출력 됨 )

또는

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

(각각 단일 공백으로 구분 된 문자열 슬라이스 요소를 출력합니다) 예를 들어 문자열 구분 기호가있는 문자열 패키지의 Join 함수를 사용 합니다 .


답변

리플렉션을 사용하는 것이 가능하다고 생각하지만 좋은 해결책인지 모르겠습니다

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

산출:

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


답변

fmt.Println소요 가변 매개 변수를

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

flag.Args()변환없이 인쇄 가능[]interface{}

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


답변