将泛型类型添加到 Dart 中的可比较类型
Adding the generic type to a comparable type in Dart
这是阅读此问答后的后续问题:
我有一个 class 像这样:
class BinarySearchTree<E extends Comparable> { ... }
所以我可以像这样创建一个实例:
final tree = BinarySearchTree<int>();
我的问题是关于使用 Comparable
与 Comparable<E>
。当我这样做时:
class BinarySearchTree<E extends Comparable> { ... }
则类型默认为E extends Comparable<dynamic>
。我通常尽量避免 dynamic
,所以为了更明确地说明正在比较的类型,我似乎应该这样写:
class BinarySearchTree<E extends Comparable<E>> { ... }
但在那种情况下,我在这里得到一个错误:
final tree = BinarySearchTree<int>();
// 'int' doesn't conform to the bound 'Comparable<int>' of the type parameter 'E'.
// Try using a type that is or is a subclass of 'Comparable<int>'.
这表明我对泛型缺乏理解。我错过了什么?
在 Dart 中,class 不能实现通用接口的 2 个不同的具体实例:
abstract class Foo<T> {}
// error: Foo can only be implemented once
class Bar implements Foo<String>, Foo<int> {}
num
实现了 Comparable<num>
,因为内置数字类型不可比较有点荒谬。但是,由于 int
是 num
的子类型(因此继承了 Comparable<num>
,它不能有 Comparable<int>
.
这导致 int
没有实现 Comparable<int>
.
的稍微奇怪的结果
你面临的问题是,从语言的角度来看,涉及两种类型:被比较的元素的类型,以及它们被比较的元素的类型。
因此,您的类型将需要 2 个类型参数:
class Tree<T extends Comparable<S>, S> {
T get foo;
}
final intTree = Tree<int, num>();
final foo = intTree.foo; // returns an int
诚然,这不是一个超级干净的解决方案,但如果您使用的是 Dart 2.13 或更高版本,则可以使用 typedef 使其更好一些:
typedef IntTree = Tree<int, num>;
typedef RegularTree<T> = Tree<T, T>;
final intTree = IntTree();
final stringTree = RegularTree<String>();
intTree.foo // is an int
stringTree.foo // is a String
还有另一种选择,就是放弃一些类型安全并使用 Comparable<dynamic>
,但我个人不建议这样做。顺便说一句,如果你想避免意外丢失类型参数,你可以禁用 implicit-dynamic
,如下所述:https://dart.dev/guides/language/analysis-options#enabling-additional-type-checks
每当从上下文中推断类型 dynamic
而程序员实际上没有输入单词 dynamic
时,这将给出错误
这是阅读此问答后的后续问题:
我有一个 class 像这样:
class BinarySearchTree<E extends Comparable> { ... }
所以我可以像这样创建一个实例:
final tree = BinarySearchTree<int>();
我的问题是关于使用 Comparable
与 Comparable<E>
。当我这样做时:
class BinarySearchTree<E extends Comparable> { ... }
则类型默认为E extends Comparable<dynamic>
。我通常尽量避免 dynamic
,所以为了更明确地说明正在比较的类型,我似乎应该这样写:
class BinarySearchTree<E extends Comparable<E>> { ... }
但在那种情况下,我在这里得到一个错误:
final tree = BinarySearchTree<int>();
// 'int' doesn't conform to the bound 'Comparable<int>' of the type parameter 'E'.
// Try using a type that is or is a subclass of 'Comparable<int>'.
这表明我对泛型缺乏理解。我错过了什么?
在 Dart 中,class 不能实现通用接口的 2 个不同的具体实例:
abstract class Foo<T> {}
// error: Foo can only be implemented once
class Bar implements Foo<String>, Foo<int> {}
num
实现了 Comparable<num>
,因为内置数字类型不可比较有点荒谬。但是,由于 int
是 num
的子类型(因此继承了 Comparable<num>
,它不能有 Comparable<int>
.
这导致 int
没有实现 Comparable<int>
.
你面临的问题是,从语言的角度来看,涉及两种类型:被比较的元素的类型,以及它们被比较的元素的类型。
因此,您的类型将需要 2 个类型参数:
class Tree<T extends Comparable<S>, S> {
T get foo;
}
final intTree = Tree<int, num>();
final foo = intTree.foo; // returns an int
诚然,这不是一个超级干净的解决方案,但如果您使用的是 Dart 2.13 或更高版本,则可以使用 typedef 使其更好一些:
typedef IntTree = Tree<int, num>;
typedef RegularTree<T> = Tree<T, T>;
final intTree = IntTree();
final stringTree = RegularTree<String>();
intTree.foo // is an int
stringTree.foo // is a String
还有另一种选择,就是放弃一些类型安全并使用 Comparable<dynamic>
,但我个人不建议这样做。顺便说一句,如果你想避免意外丢失类型参数,你可以禁用 implicit-dynamic
,如下所述:https://dart.dev/guides/language/analysis-options#enabling-additional-type-checks
每当从上下文中推断类型 dynamic
而程序员实际上没有输入单词 dynamic