[go] 인터페이스 변환 유형 변환

Go가 암시 적으로 변환 []T[]interface{}때 암시 적으로 변환하지 않는 이유가 궁금 T합니다 interface{}. 누락 된이 전환에 대해 사소한 것이 있습니까?

예:

func foo([]interface{}) { /* do something */ }

func main() {
    var a []string = []string{"hello", "world"}
    foo(a)
}

go build 불평하다

함수 인수에서 (] [type]을 (를) 유형 [] 인터페이스 {}로 사용할 수 없습니다.

그리고 명시 적으로하려고하면 동일한 일이 b := []interface{}(a)불평합니다.

(유형 [] 문자열)을 유형 [] 인터페이스 {} (으)로 변환 할 수 없습니다

그래서이 변환을해야 할 때마다 (많은 것으로 보입니다), 나는 다음과 같은 일을하고 있습니다 :

b = make([]interface{}, len(a), len(a))
for i := range a {
    b[i] = a[i]
}

이 작업을 수행하는 더 좋은 방법이나 이러한 변환에 도움이되는 표준 라이브러리 기능이 있습니까? 정수 또는 문자열 목록을 가져올 수있는 함수를 호출 할 때마다 4 개의 추가 코드 줄을 작성하는 것은 어리석은 것처럼 보입니다.



답변

Go에는 구문이 복잡하고 비용이 많이 드는 작업을 숨겨서는 안된다는 일반적인 규칙이 있습니다. a string로 변환하는 interface{}것은 O (1) 시간 안에 이루어집니다. A 변환 []string내지 An은 interface{}슬라이스는 여전히 하나 개의 값이기 때문에 같은 O (1) 시간 수행된다. 그러나 슬라이스의 각 요소를로 변환해야하기 때문에 a []string를 a () 로 변환하는 []interface{}시간은 O (n) interface{}입니다.

이 규칙의 한 가지 예외는 문자열 변환입니다. a string를 a []byte또는 a 로 변환 할 때 변환 []rune이 “구문”인 경우에도 O (n)이 작동합니다.

이 변환을 수행 할 표준 라이브러리 기능은 없습니다. 리플렉션으로 만들 수는 있지만 3 줄 옵션보다 느립니다.

리플렉션이 포함 된 예 :

func InterfaceSlice(slice interface{}) []interface{} {
    s := reflect.ValueOf(slice)
    if s.Kind() != reflect.Slice {
        panic("InterfaceSlice() given a non-slice type")
    }

    ret := make([]interface{}, s.Len())

    for i:=0; i<s.Len(); i++ {
        ret[i] = s.Index(i).Interface()
    }

    return ret
}

가장 좋은 방법은 질문에 제공 한 코드 줄을 사용하는 것입니다.

b := make([]interface{}, len(a))
for i := range a {
    b[i] = a[i]
}


답변

누락되는 일이 있다는 것입니다 Tinterface{}값 보유하고있는 T메모리의 다른 표현이 너무 하찮게 변환 할 수없는 한을.

유형의 변수는 T메모리의 값입니다. 연관된 유형 정보가 없습니다 (Go에서는 모든 변수에 런타임 시가 아닌 컴파일 타임에 알려진 단일 유형이 있음). 다음과 같이 메모리에 표시됩니다.

interface{}형 들고 변수는 T이와 같은 메모리에 표현되는

  • 유형에 대한 포인터 T

그래서 원래의 질문에 돌아 오는 왜 이동 does’t 암시 적 변환 []T[]interface{}?

메모리 내 레이아웃이 완전히 다르기 때문에 사소한 작업 인 새 값 조각을 만들려면 변환 []T해야 합니다.[]interface{}interface {}


답변

공식 설명은 다음과 같습니다. https://github.com/golang/go/wiki/InterfaceSlice

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
    interfaceSlice[i] = d
}


답변

interface{}대신 시도하십시오 . 슬라이스로 다시 캐스팅하려면

func foo(bar interface{}) {
    s := bar.([]string)
    // ...
}


답변

interface{}모든 유형으로 변환하십시오 .

통사론:

result := interface.(datatype)

예:

var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string)   //result type is []string.


답변

코드를 더 단축해야하는 경우 도우미를위한 새로운 유형을 만들 수 있습니다.

type Strings []string

func (ss Strings) ToInterfaceSlice() []interface{} {
    iface := make([]interface{}, len(ss))
    for i := range ss {
        iface[i] = ss[i]
    }
    return iface
}

그때

a := []strings{"a", "b", "c", "d"}
sliceIFace := Strings(a).ToInterfaceSlice()


답변