슬라이스를 저장하는 interface {}를 통한 범위


99

허용하는 함수가있는 시나리오가 주어지면 t interface{}. 이 t조각 이라고 판단되면 해당 조각을 어떻게 range덮어야합니까?

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(data)
}

func test(t interface{}) {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        // how do I iterate here?
        for _,value := range t {
            fmt.Println(value)
        }
    }
}

Go Playground 예 : http://play.golang.org/p/DNldAlNShB


함수가 대신 [] 인터페이스 {}를 사용하지 않는 이유는 무엇입니까? 여러 복합 유형을 처리하려고합니까?
Jeremy Wall

2
예, 템플릿 시스템을위한 것이므로 interface {}는 맵, 구조체, 슬라이스 또는 배열이 될 수 있습니다. 실제 코드에는 더 많은 case 문이 있지만 문제를 더 간결하게 만들기 위해 게시물에서 제거했습니다.
Nucleon

1
Jeremy, [] 문자열은 [] 인터페이스 {}의 하위 유형이 아니므로 [] 문자열 또는 [] int 등을 사용하여 func ([] 인터페이스 {}) 함수를 호출 할 수 없습니다. Go에 "어떤 것의 조각"을 의미하는 유형을 갖는 기능이 있습니다. 그런 다음 인터페이스 {}로 요소를 반복 할 수 있지만 불행히도 이에 대한 반영이 필요합니다.
Bjarke Ebert

@JeremyWall [] 인터페이스 {}를 사용하여 슬라이스 역할을 할 수 없습니다. 여기에서 참조 할 수 있습니다 .
firelyu

답변:


138

그럼 난 사용 reflect.ValueOf후는 슬라이스 인 경우는 호출 할 수 있습니다 Len()Index()얻을 수있는 값에 len인덱스에 슬라이스와 요소를. 나는 당신이 이것을하기 위해 범위 작동을 사용할 수 없을 것이라고 생각합니다.

package main

import "fmt"
import "reflect"

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(moredata)
} 

func test(t interface{}) {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(t)

        for i := 0; i < s.Len(); i++ {
            fmt.Println(s.Index(i))
        }
    }
}

Go Playground 예 : http://play.golang.org/p/gQhCTiwPAq


25
훌륭하게 작동합니다. 감사합니다. 추가 할 유일한 것은 s.Index(i)a 를 반환하는 reflect.Value것이므로 제 경우 s.Index(i).Interface()에는 실제 값을 참조 해야 했습니다.
핵자

1
슬라이스에 대한 포인터가 있다면 interface{}어떻게 하시겠습니까? 예를 들면 moredata := &[]int{1,2,3}
라이언 벽

1
내 질문에 답하기 : 슬라이스 대신 슬라이스에 대한 포인터가있는 Elem()경우 기본 값을 가져 오는 데를 사용해야 합니다. 예를 들면 reflect.TypeOf(reflect.ValueOf(t).Elem().Interface()).Kind()
라이언 벽

구조체없이 인터페이스 조각에서 인터페이스 필드의 값을 얻으려면 어떻게해야합니까? 이 솔루션을 시도했지만 필드의 실제 값이 아닌 슬라이스에서만 인터페이스 참조를 얻는 것으로 제한됩니다.
Amandeep 카 우르

감사합니다. 그 트릭으로 많은 시간과 두통이 절약되었습니다.
Nicolas Garnier

26

예상되는 유형을 알고 있으면 리플렉션을 사용할 필요가 없습니다. 다음 과 같이 유형 스위치를 사용할 수 있습니다 .

package main

import "fmt"

func main() {
    loop([]string{"one", "two", "three"})
    loop([]int{1, 2, 3})
}

func loop(t interface{}) {
    switch t := t.(type) {
    case []string:
        for _, value := range t {
            fmt.Println(value)
        }
    case []int:
        for _, value := range t {
            fmt.Println(value)
        }
    }
}

놀이터에서 코드를 확인하십시오 .


이것은 어레이에서는 작동하지 않고 슬라이스에서만 작동합니다
user1028741

@ user1028741 아니요, 코드는 배열을 포함한 모든 유형에서 작동합니다. + 항상 배열에서 슬라이스를 가져올 수 있습니다 array[:].
Inanc Gumus

그러나 어레이의 유형은 실제 용량과 같습니다. [3] int는 [2] int 또는 [] int와 동일한 유형이 아닙니다. 따라서 't'의 유형이 실제로 배열 인 경우 관련 사례가 적용되지 않습니다.
user1028741

1
내 말은 귀하의 예제가 배열에서 작동하지 않는다는 것입니다. 여기에서 변경했습니다 : play.golang.org/p/DAsg_0aXz-r
user1028741

처음에 매개 변수의 유형을 모르면 쉽게 작동하도록 만들 수 없습니다. 트릭 (array [:])을 사용하려면 리플렉션을 사용하여 배열인지 결정한 다음 배열로 캐스트 한 다음 슬라이스를 생성해야합니다. 그것이 내가 배열이 아닌 슬라이스에서 작동한다고 말한 이유입니다. 충분한 노력을 기울이면 어레이에서 슬라이스를 생성 할 수 있습니다.
user1028741

4

interface {}가 동작하는 방식에는 한 가지 예외가 있습니다. @Jeremy Wall은 이미 포인터를 제공했습니다. 전달 된 데이터가 처음에 [] interface {}로 정의 된 경우.

package main

import (
    "fmt"
)

type interfaceSliceType []interface{}

var interfaceAsSlice interfaceSliceType

func main() {
    loop(append(interfaceAsSlice, 1, 2, 3))
    loop(append(interfaceAsSlice, "1", "2", "3"))
    // or
    loop([]interface{}{[]string{"1"}, []string{"2"}, []string{"3"}})
    fmt.Println("------------------")


    // and of course one such slice can hold any type
    loop(interfaceSliceType{"string", 999, map[int]string{3: "three"}})
}

func loop(slice []interface{}) {
    for _, elem := range slice {
        switch elemTyped := elem.(type) {
        case int:
            fmt.Println("int:", elemTyped)
        case string:
            fmt.Println("string:", elemTyped)
        case []string:
            fmt.Println("[]string:", elemTyped)
        case interface{}:
            fmt.Println("map:", elemTyped)
        }
    }
}

산출:

int: 1
int: 2
int: 3
string: 1
string: 2
string: 3
[]string: [1]
[]string: [2]
[]string: [3]
------------------
string: string
int: 999
map: map[3:three]

그것을 시도

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