# #go #pointers #reflection #slice
Вопрос:
Я знаю, как проверить, является ли интерфейс указателем:
func isPointerArray(i interface{}) bool {
if i == nil {
return false
}
if reflect.ValueOf(i).Kind() != reflect.Ptr {
return false
}
}
Но как я могу проверить, является ли этот указатель срезом? TypeOf
является указателем.
Ответ №1:
Если вид значения reflect.Ptr
равен, вы можете использовать Value.Elem()
для получения указанного значения, и вы можете сравнить его вид с reflect.Slice
.
Вот как это будет выглядеть:
func isPtrSlice(i interface{}) bool {
if i == nil {
return false
}
v := reflect.ValueOf(i)
if v.Kind() != reflect.Ptr {
return false
}
return v.Elem().Kind() == reflect.Slice
}
Но есть одна загвоздка. Если переданное значение является указателем на тип среза, но само значение является nil
указателем, об этом будет сообщено false
. Понятно, поскольку нет указанного значения, тип которого мог бы быть срезом. Это может быть или не быть тем, что вы хотите.
Если вы хотите true
даже для nil
значений указателя (которые относятся к типам указателей на срезы), вы можете использовать reflect.Type
вместо reflect.Value
. Это работает и для nil
указателей, потому что, несмотря на отсутствие указанного значения, все еще существует указанный тип (называемый базовым типом).
func isPtrSlice2(i interface{}) bool {
if i == nil {
return false
}
t := reflect.TypeOf(i)
if t.Kind() != reflect.Ptr {
return false
}
return t.Elem().Kind() == reflect.Slice
}
Тестирование вышеуказанных функций:
vals := []interface{}{
nil,
"a",
amp;image.Point{},
[]string{},
amp;[]string{},
(*[]string)(nil),
}
for _, v := range vals {
fmt.Printf("%-14T isPtrSlice: %-5t, isPtrSlice2: %tn",
v, isPtrSlice(v), isPtrSlice2(v))
}
Который будет выводиться (попробуйте это на игровой площадке Go):
<nil> isPtrSlice: false, isPtrSlice2: false
string isPtrSlice: false, isPtrSlice2: false
*image.Point isPtrSlice: false, isPtrSlice2: false
[]string isPtrSlice: false, isPtrSlice2: false
*[]string isPtrSlice: true , isPtrSlice2: true
*[]string isPtrSlice: false, isPtrSlice2: true
Как вы можете видеть в последней строке (где значение является nil
указателем типа *[]string
) isPtrSlice()
, возвращает false
while isPtrSlice2()
returns true
.
Комментарии:
1. для массивов можно использовать
reflect.Array
, напримерelem.Kind() == reflect.Slice || elem.Kind() == reflect.Array
2. какой-то качественный ответ icza прямо там. Спасибо
Ответ №2:
Вы можете использовать утверждения типа:
package main
import "fmt"
func main() {
var value interface{}
value = amp;[]int{1, 2}
if res, ok := value.(*[]int); ok {
fmt.Println(res)
}
}
Комментарии:
1. Одним из ограничений является то, что я не знаю тип.