英文:
In Golang, how to compare interface as generics type to nil?
问题
我需要一个链接节点来保存一些不同的接口类型,所以我使用了泛型来创建它,但是泛型类型any
不能与nil
进行比较,会显示错误,如下所示:
package main
type myInterface interface {
}
type node[T any] struct {
next *node[T]
leaf T
}
func (n *node[T]) GetFirstNodeHasLeaf() *node[T] {
if n.leaf != nil { // <---- error here: cannot compare n.leaf != nil (mismatched types T and untyped nil)
return n
}
if n.next == nil {
return nil
} else {
return n.next.GetFirstNodeHasLeaf()
}
}
func main() {
var n = &node[myInterface]{}
// fill n with lots of nodes
n.GetFirstNodeHasLeaf() // get the first node that has (leaf != nil)
}
我还尝试了与默认值进行比较:
var nilT T
if n.leaf != nilT { // <-- same problem
并且将节点类型限制为:
type node[T myInterface] struct {
仍然出现相同的错误,请问如何解决这个问题?谢谢。
英文:
I need a linked node to hold some different interface types, so I made it with generics, but the generics type any
can't be compared to nil, it shows error as in the comment:
package main
type myInterface interface {
}
type node[T any] struct {
next *node[T]
leaf T
}
func (n *node[T]) GetFirstNodeHasLeaf() *node[T] {
if n.leaf != nil { // <---- error here: cannot compare n.leaf != nil (mismatched types T and untyped nil)
return n
}
if n.next == nil {
return nil
} else {
return n.next.GetFirstNodeHasLeaf()
}
}
func main() {
var n = &node[myInterface]{}
// fill n with lots of nodes
n.GetFirstNodeHasLeaf() // get the first node that has (leaf != nil)
}
I also tried to compare with a default value
var nilT T
if n.leaf != nilT { // <-- same problem
And restrict the node type as
type node[T myInterface] struct {
Same error, how to solve this? Thanks.
答案1
得分: 6
使用接口来实例化泛型类型node
可能是一个概念上的缺陷。所以我们先看一下一般情况,最后再看接口的情况。
使用comparable
和T
如果你想要在类型参数类型的值上使用等号操作符==
和!=
,约束条件必须是comparable
。
type node[T comparable] struct {
next *node[T]
leaf T
}
但是你不会对nil
进行测试,你会对T
的零值进行测试,这取决于你实例化它时使用的值,可能不是nil
。
在这种情况下,你可以声明一个类型为T
的变量来表示它的零值:
var zero T
if n.leaf != zero {
return n
}
然而,接口类型不实现comparable
。
使用any
和*T
作为替代方案,你可以保持约束条件为any
,并将字段leaf
声明为指向T
的指针。这样就支持等号操作符,因为leaf
的类型不再是类型参数,而是一个指针:
type node[T any] struct {
next *node[T]
leaf *T
}
func (n *node[T]) GetFirstNodeHasLeaf() *node[T] {
if n.leaf != nil { // ok, leaf is a pointer type
return n
}
...
}
使用any
和T
在约束条件为any
的情况下,T
不支持等号操作符;你可以使用任意类型来实例化node
,包括那些不可比较的类型。
只要字段不是指针,你只能使用反射来检查零值(对于指针类型来说是nil
):
if !reflect.ValueOf(n.leaf).IsZero() {
return n
}
最后,请注意上述代码在T
是接口类型时不起作用。被测试的是接口中封装的动态值。如果T
必须是一个接口,可以使用以下代码来测试零值:
// leaf是一个接口类型
if !reflect.ValueOf(&n.leaf).Elem().IsZero() {
return n
}
英文:
Using an interface to instantiate a generic type like node
is probably a conceptual flaw. So let's see the general cases first, and the interface case at the end.
Using comparable
and T
If you want to use equality operators like ==
and !=
with values of type parameter type, the constraint must be comparable
.
type node[T comparable] struct {
next *node[T]
leaf T
}
but then you're not going to test against nil
, you would test against T
's zero value, which, depending on what you instantiate it with, could be something other than nil
.
In that case you would declare a variable of type T
for its zero value:
var zero T
if n.leaf != zero {
return n
}
However interface types don't implement comparable
.
Using any
and *T
As an alternative, you can keep the constraint any
and declare the field leaf
as a pointer to T
. That supports equality operators, because leaf
type isn't a type parameter anymore, it's a pointer:
type node[T any] struct {
next *node[T]
leaf *T
}
func (n *node[T]) GetFirstNodeHasLeaf() *node[T] {
if n.leaf != nil { // ok, leaf is a pointer type
return n
}
...
}
Using any
and T
With the constraint any
, T
doesn't support the equality operators; you could instantiate node
with literally any type, including those that aren't comparable.
As long as the field isn't a pointer, you can only use reflection to check for the zero value (nil
for pointer types`):
if !reflect.ValueOf(n.leaf).IsZero() {
return n
}
Finally, consider that the above code doesn't work if T
is an interface type. What is tested is the dynamic value boxed in the interface. If T
really must be an interface, test for the zero value with:
// leaf is an interface type
if !reflect.ValueOf(&n.leaf).Elem().IsZero() {
return n
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论