6

一个常见的问题,特别是自 Dart 2 以来,是否可以在某些或所有类型上要求某些或所有泛型类型参数 - 例如List<int>代替ListMyType<Foo>代替MyType.

虽然并不总是很清楚意图是什么 - 即这是一个风格问题(您/您的团队喜欢查看类型),以防止错误(省略类型参数似乎会给您/您的团队带来更多错误),或者作为合同问题(您的库需要类型参数)。

例如,在 上dart-misc,用户写道:

基本上,如果我有这个:

abstract class Mixin<T> {}

不必指定类型:

// Works class Cls extends Object with Mixin<int> {} // ...also works
class Cls extends Object with Mixin {}

有没有办法让第二个不允许?

4

1 回答 1

14

严格来说,有,没有。

如果您想强制在您自己的项目中始终使用类型参数(而不是依赖类型推断或默认值),您可以使用可选 的 linter 规则,例如always_specify_types. AVOID redundant type arguments on generic invocations请注意,此规则在许多情况下违反了官方 Dart 样式指南的建议。

如果您想强制在默认值令人困惑始终使用泛型类型参数- 例如隐含含义,尚不存在这样的 lint - 尽管我们计划将其添加为分析器的模式: https ://github.com /dart-lang/sdk/issues/33119ListList<dynamic>


以上两个建议都会对您自己有所帮助,但是如果您正在创建一个库供其他人使用,您可能会问是否可以要求类型参数来使用您的类。例如,从上面:

abstract class Mixin<T> {}
abstract class Class extends Object with Mixin {}

您可以做的第一件事是将默认边界添加到T

// If T is omitted/not inferred, it defaults to num, not dynamic.
abstract class Mixin<T extends num> {}

如果你想允许任何东西,但又想让你的类/mixin在动态时难以使用,T你可以选择不同的默认边界,例如Object,甚至更好,我建议void

在实践中,我习惯于void表示“任何事情,我不关心元素”

abstract class Mixin<T extends void> {
  T value;
}

class Class extends Mixin {}

void main() {
  var c = Class();
  // Compile-time error: 'oops' isn't defined for the class 'void'.
  c.value.oops();
}

(您也可以Object用于此目的)

如果这是您控制的类,您可以添加一个断言,以防止该类以您不支持或不期望的方式使用。例如:

class AlwaysSpecifyType<T> {
  AlwaysSpecifyType() {
    assert(T != dynamic);
  }
}

最后,您可以编写自定义 lint 或工具来禁止省略某些泛型类型参数,但这可能是最大的工作量,如果前面的任何方法对您有用,我强烈推荐这些方法!

于 2018-09-12T01:17:10.150 回答