2016-02-10 3 views
3

У меня есть interface{} переменная, и я знаю, что это указатель на срез:интерфейс {} переменная [] Интерфейс {}

func isPointerToSlice(val interface{}) bool { 
    value := reflect.ValueOf(val) 
    return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice 
} 

Но я нахожу, что трудно ввести брось в []interface{} переменной:

if isPointerToSlice(val) { 
    slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{}) 
    // 'worked' is false :(
} 

Это не работает. Любая идея, как я могу это решить?

ответ

1

Вы можете просто использовать type assertion для получения значения, хранящегося в интерфейсе, например.

if isPointerToSlice(val) { 
    var result []interface{} 
    result = *val.(*[]interface{}) 
    fmt.Println(result) 
} else { 
    fmt.Println("Not *[]interface{}") 
} 

Тип значения, хранимого в интерфейсе, как вы утверждаете, является указателем на []interface{}, который *[]interface{}. Результат утверждения типа будет указателем, просто разыщите его, чтобы получить фрагмент []interface{}.

Использование short variable declaration:

result := *val.(*[]interface{}) // type of result is []interface{} 

Попробуйте на Go Playground.


Кроме того, ваша попытка также работает:

slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{}) 
fmt.Println(slice, worked) 

Вот edited the Playground example что доказывает ваше решение работает.

Но использование отражения не является необходимым (как это может быть сделано с утверждением типа).

Также отметим, что *[]interface{} и *[]someOtherType 2 различных типов, и вы не можете получить значение *[]interface{}, если есть что-то еще в val.

+0

@izca, в моем конкретном примере это ошибка с этой ошибкой 'interface conversion: interface {} is * [] util.sample, not * [] interface {}' –

+1

@PabloFernandez '* [] util.sample' и '* [] interface {}' - 2 разных типа.Если ваш 'val' содержит значение типа' * [] util.sample', вы можете получить из него значение '* [] util.sample'. – icza

1

Если вы просто хотите, чтобы преобразовать ломтик []interface{} вы можете использовать что-то вроде этого:

func sliceToIfaceSlice(val interface{}) []interface{} { 
    rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer 
    if k := rf.Kind(); k != reflect.Slice && k != reflect.Array { 
     // panic("expected a slice or array") 
     return nil 
    } 
    out := make([]interface{}, rf.Len()) 
    for i := range out { 
     out[i] = rf.Index(i).Interface() 
    } 
    return out 
} 

playground

0

ответ Icza является большим и будет работать, особенно если вы не можете знать, что вы получают срединный интерфейс, однако, если вы вообще не хотите беспокоиться об отраженном пакете и хотите сохранить низкий уровень импорта, вы можете использовать коммутацию типов для получения той же функциональности, используя только встроенные методы.

Используя этот метод, вы можете сократить ваш код просто:

package main 

import (
    "fmt" 
) 

func main() { 
    s := []interface{}{"one", 2} 
    p := &s 

    do(p) 
} 

func do(val interface{}) { 
    switch val.(type){ 
    case *[]interface{}: 
     var result []interface{} 
     result = *val.(*[]interface{}) 
     fmt.Println(result) 
    } 
} 

площадка: http://play.golang.org/p/DT_hb8JcVt

Недостатком является то, если вы не знаете точный тип среза вы получаете заранее, то это не сработает, если вы не перечислите все возможные типы обработки и утверждения.

Смежные вопросы