【问题标题】:Limit a generic type argument only to be a int, double or custom class将泛型类型参数限制为 int、double 或自定义类
【发布时间】:2019-07-17 16:39:20
【问题描述】:

我尝试编写以下代码,但 T 只能是 int、double 或自定义类。我找不到如何限制 Dart 中的类型或 C# 中的 where 之类的东西。我怎样才能在 Dart 中做到这一点?

class Array3dG<T> extends ListBase<T> {
  List<T> l = List<T>();
  Array3dG(List<T> list) {
    l = list;
  }
  set length(int newLength) { l.length = newLength; }
  int get length => l.length;
  T operator [](int index) => l[index];
  void operator []=(int index, T value) { l[index] = value; }
}

【问题讨论】:

  • 当您说“自定义类”时,这意味着什么?对我来说,这听起来像任何类,所以问题应该更多是什么让这个“自定义类”特别?
  • 在这种情况下,是我自己创建的另一个类来处理列表:class Array1dG&lt;T&gt; extends ListBase&lt;T&gt; ... 。这个类没有什么特别之处,只是另一个类。
  • 如果课程没有什么特别之处,为什么不允许所有课程?我的意思是,如果你对类有一些要求,你可以将其指定为 。我只是想了解问题,以便提供最佳解决方案。正如您所提到的,Dart 没有来自 C# 的“位置”。
  • 就我而言,我的班级只能处理数字类型或某些也可以处理数字的特定类型的班级。例如,如果用户输入 T = String,则所有类都会中断,因此我想限制 T 的可能类型。我想解决这个问题,在构造函数中检查类型 T 并抛出异常,但我如果这是一个好的解决方案,请不要这样做。
  • 使用 的问题是我只能从一个接口或类扩展,但就我而言,我需要允许多个类型。

标签: dart


【解决方案1】:

没有办法在编译时约束类型变量。类型变量只能有一个边界,同时满足int 和自定义类的唯一边界是Object

正如@Mattia 所建议的,如果类型参数不是你支持的参数之一,你可以在运行时检查并抛出构造函数:

Array3dG(this.list) { 
  if (this is! Array3dG<int> && 
      this is! Array3dG<double> && 
      this is! Array3dG<MyClass>) {
    throw ArgumentError('Unsupported element type $T');
  }
}

这可以防止创建错误的实例,但不会在编译时捕获它。

另一种选择是使用工厂方法而不是构造函数:

class Array3dG<T> {
  List<T> list;
  Array3dG._(this.list);
  static Array3dG<int> fromInt(List<int> list) => Array3dG<int>._(list);      
  static Array3dG<int> fromDouble(List<double> list) => Array3dG<double>._(list);      
  static Array3dG<MyClass> fromMyClass(List<MyClass> list) => Array3dG<MyClass>._(list);
  ...
}

然后您将其用作Array3dG.fromInt(listOfInt)。它看起来像一个命名构造函数,但它只是一个静态工厂方法(所以前面没有使用new)。

【讨论】:

  • 你知道 Dart lang 是否有任何提议在编译时支持这个验证?
  • 天啊,它从 2018 年 11 月开始营业!如此低的优先级不会很快解决。
  • 很可能是正确的。这是该语言的一项开放功能请求,是众多功能之一。尚未有人承诺将其实际添加到该语言中,并且它不是当前正在研究的最高优先级功能之一。所以是的,它可能永远不会发生 - 或者如果该功能由于某种原因成为高优先级,它可能会很快发生。 (这几乎描述了当前未积极处理的每个语言功能请求)。
【解决方案2】:

您可以在运行时使用 is 关键字检查类型:

Array3dG(List<T> list) {
   if (list is List<int>) {
        //Handle int
   }
   else if (list is List<double>) {
        //Handle double
   }
   else if (list is List<MyClass>) {
        //Handle MyClass
   }
   else {
       throw ArgumentError('Unsupported $T type');
   }
  }

请注意,如果您以相同的方式处理intdouble,则只需检查num

您可以在这里查看联合类型的进度:https://github.com/dart-lang/sdk/issues/4938

【讨论】:

  • 谢谢,我认为运行时检查类型是唯一的解决方案。您可以编辑您的答案并将最后一个 else if 更改为 elseelse if (T is MyClass2) 吗?
  • 哦,那是复制粘贴时的类型,我已经编辑了答案
  • 此代码不起作用。您正在检查具有 Type 类型的表达式 T 的类型,而不是类型变量是否是上述类型的子类型。 (另外,永远不要抛出Exception,使用Error 表示编程错误。这可能是ArgumentError)。
  • @lrn 感谢您的帮助,现在代码应该可以正常使用了
猜你喜欢
  • 2011-02-08
  • 2017-11-17
  • 1970-01-01
  • 1970-01-01
  • 2021-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多