인터페이스 변환 유형 변환


194

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 개의 추가 코드 줄을 작성하는 것은 어리석은 것처럼 보입니다.


따라서 "새 슬라이스를 할당하고 모든 요소를 ​​복사"한다는 의미로 "[] T를 [] interface {}로 암시 적으로 변환"으로 정의합니다. "T를 인터페이스로 암시 적으로 변환 {}"하는 것과 일치하지 않습니다. 이는보다 일반적인 정적 유형과 동일한 값의보기 일뿐입니다. 아무것도 복사되지 않습니다. 그리고 T 타입으로 타입 어설 션을하더라도 여전히 같은 결과를 얻게됩니다.
newacct

1
구현 방법에 대해 너무 자세하게 생각하지 않고 상위 레벨에서는 일반 유형을 갖지 않는 해결 방법으로 전체 목록을 다른 유형으로 쉽게 변환 할 수 있다는 것이 편리합니다.
danny

답변:


215

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

3
속도는 느릴 수 있지만 모든 종류의 슬라이스에서 일반적으로 작동합니다.
newacct

이 전체 답변은 mapbtw 에도 적용됩니다 .
RickyA

이것은 또한 적용됩니다 channels.
저스틴 옴

가능한 경우 심판을 추가 할 수있는 명확한 설명 주셔서 감사합니다. 에 대한 Converting a []string to an interface{} is also done in O(1) time?
Mayur

56

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

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

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

  • 유형에 대한 포인터 T

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

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


10
이것은 유익하고 잘 쓰여져 있지만 (+1), 당신은 그의 질문의 다른 부분을 다루지 않고 있습니다 : "이걸하는 더 좋은 방법이 있습니까?"
weberc2

13

공식 설명은 다음과 같습니다. 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
}

좋은 정보이지만 공식적인 설명은 아닙니다. 누구나 편집 할 수있는 위키입니다.
Inanc Gumus

어떻게 []interface예상되는 유형으로 변환해야 []map[string]interface{}합니까?
Lewis Chan

8

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

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

3
이것은 다음 질문을 제기한다. OP가 어떻게 bar"모든 유형의 슬라이스"로 해석되도록 OP를 반복해야 하는가? 그의 세 라이너가 생성합니다 []interface{},하지 []string또는 다른 구체적인 형태의 조각.
kostix

14
-1 : bar가 [] 문자열 인 경우에만 작동합니다.이 경우 다음과 같이 쓸 수도 있습니다.func foo(bar []string) { /* ... */ }
weberc2

2
형식 스위치를 사용하거나 허용되는 답변과 같이 반사를 사용하십시오.
dskinner

OP는 어떤 식 으로든 런타임에 자신의 유형을 파악해야합니다. 비 슬라이스 interface{}를 사용하면 에서와 같이 인수를 전달할 때 컴파일러가 불평하지 않습니다 foo(a). 그는 내부에서 reflect 또는 type 전환 ( golang.org/doc/effective_go.html#type_switch )을 사용할 수 있습니다 foo.
Cassiohg '

2

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

통사론:

result := interface.(datatype)

예:

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

2
그것에 대하여 확신하나요? 나는 이것이 유효하다고 생각하지 않습니다. 당신은 그것을 볼 것입니다 : invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Adriano Tadao

2

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

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()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.