Мне нужен связанный узел для хранения нескольких разных типов интерфейса, поэтому я сделал его с помощью дженериков, но тип дженериков 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 {
Такая же ошибка, как решить? Спасибо.
Использование интерфейса для создания универсального типа, такого как 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 больше не параметр типа, а указатель:
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 is an interface type
if !reflect.ValueOf(&n.leaf).Elem().IsZero() {
return n
}