如何检查接口是否是指向切片的指针

huangapple go评论71阅读模式
英文:

How to check if interface is a a pointer to a slice

问题

我知道如何检查接口是否为指针:

func isPointerArray(i interface{}) bool {
    if i == nil {
        return false
    }
    if reflect.ValueOf(i).Kind() != reflect.Ptr {
        return false
    }
}

但是,我该如何检查该指针是否为切片?TypeOf 是一个指针。

英文:

I know how to check if an interface is a pointer:

func isPointerArray(i interface{}) bool {
	if i == nil {
		return false
	}
	if reflect.ValueOf(i).Kind() != reflect.Ptr {
		return false
	}
}

But how can I check if that pointer is a slice? TypeOf is a pointer.

答案1

得分: 6

如果值的类型是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。可以理解,因为没有指向的值其类型可能是切片。这可能是你想要的,也可能不是。

如果你希望即使对于nil指针值(指向切片类型的指针),也返回true,你可以使用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",
    &image.Point{},
    []string{},
    &[]string{},
    (*[]string)(nil),
}

for _, v := range vals {
    fmt.Printf("%-14T isPtrSlice: %-5t, isPtrSlice2: %t\n",
        v, isPtrSlice(v), isPtrSlice2(v))
}

输出结果如下(在Go Playground上尝试):

<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

正如你在最后一行中看到的(其中值是类型为*[]stringnil指针),isPtrSlice()返回false,而isPtrSlice2()返回true

英文:

If the value's kind is reflect.Ptr, you may use Value.Elem() to get the pointed value, and you may compare its kind to reflect.Slice.

This is how it would look like:

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
}

But there's one catch though. If the value passed is a pointer to slice type but the value itself is the nil pointer, this will report false. Understandable, as there is no pointed value whose type could be a slice. This may or may not be what you want.

If you want true even for nil pointer values (that are of pointer to slice types), you may use reflect.Type instead of reflect.Value. This works for nil pointers too, because even though there is no pointed value, there is still a pointed type (called the base type).

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
}

Testing the above functions:

vals := []interface{}{
	nil,
	&quot;a&quot;,
	&amp;image.Point{},
	[]string{},
	&amp;[]string{},
	(*[]string)(nil),
}

for _, v := range vals {
	fmt.Printf(&quot;%-14T isPtrSlice: %-5t, isPtrSlice2: %t\n&quot;,
	    v, isPtrSlice(v), isPtrSlice2(v))
}

Which will output (try it on the Go Playground):

&lt;nil&gt;          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

As you can see in the last line (where the value is a nil pointer of type *[]string) isPtrSlice() returns false while isPtrSlice2() returns true.

答案2

得分: 0

你可以使用type assertions

package main

import "fmt"

func main() {
	var value interface{}
	value = &[]int{1, 2}

	if res, ok := value.(*[]int); ok {
		fmt.Println(res)
	}
}
英文:

You can use type assertions:

package main

import &quot;fmt&quot;

func main() {
	var value interface{}
	value = &amp;[]int{1, 2}

	if res, ok := value.(*[]int); ok {
		fmt.Println(res)
	}
}

huangapple
  • 本文由 发表于 2021年10月22日 18:37:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/69675420.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定