Enum 作为泛型类型在 Dart 中是有效的方法吗?

问题描述 投票:0回答:1

我发现自己面临着 Dart 中涉及枚举抽象的情况。不确定首先将其标记为抽象。这是我的情况:

class Tool {
final Enum metrics;
}

enum Gram {kg, g}
enum Meter {km, m}

我希望这个

Tool
可以使用像.name这样的getter来检索枚举功能。

此外,上述方法与以下在 Dart 中使用泛型的方法有什么区别?

class Tool<T extends Enum>{
final T metrics;
}

作为这个概念的新手,有人可以提供见解和指导吗?先谢谢你了

dart enums
1个回答
0
投票

对于您的直接问题,

final Enum metrics
final T metrics
<T extends Enum>
,区别在于outside代码如何使用该类。 在类本身内部,对代码进行类型检查时,类型变量
T
并未绑定,因此它只能知道
metrics
是一个
Enum
。 类外的代码将具有类似
Tool<Gram>
的类型,在这种情况下,他们可以知道
thatObject.metrics
具有 stype
Gram
,而不仅仅是
Enum

如果有什么用途可以使用该信息,那么这很重要。

我宁愿引入指标的子类型,而不是直接使用

Enum
。可以有许多不是指标的
enum
声明,并且类型也允许这些声明。

也许可以向指标类型添加更多属性以使其有用

import "dart:math" as math;

mixin Metric<M extends Metric<M>> on Enum {
  /// Name of the unit for display.
  String get name => EnumName(this).name;

  /// The standard unit of this metric.
  ///
  /// Will have a [scale] of 0.  
  M get standardUnit;

  /// The power of 10 of the [standardUnit] that this unit represents.
  int get scale;

  /// Creates a measurement of this type.
  Measure<M> call(num value) => Measure(value, this);

  String toString() => name;
}

/// A unit of mass or weight.
enum Weight with Metric<Weight> {
  ug(-6),
  mg(-3),
  g(0),
  kg(3);

  final int scale;

  const Weight(this.scale);
  Weight get standardUnit => g;
}

/// A unit of length.
enum Length with Metric<Length> {
  m(0),
  km(3),
  cm(-2),
  mm(-3),
  nm(-6);

  final int scale;

  const Length(this.scale);
  Length get standardUnit => m;
}

class Measure<M extends Metric<M>> {
  final num value;
  final Metric<M> unit;
  Measure(this.value, this.unit);

  Measure<M> normalize() => unit.scale == 0 ? this :
      Measure<M>(value * math.pow(10, unit.scale), unit.standardUnit);

  Measure<M> operator +(Measure<M> other) {
    var scaleDelta = other.unit.scale - unit.scale;
    return Measure<M>(value + other.value * math.pow(10, scaleDelta), unit);
  }
  Measure<M> operator -(Measure<M> other) {
    var scaleDelta = other.unit.scale - unit.scale;
    return Measure<M>(value - other.value * math.pow(10, scaleDelta), unit);
  }
  Measure<M> to(M otherUnit) => unit.scale == otherUnit.scale
      ? this
      : Measure<M>(
          value * math.pow(10, unit.scale - otherUnit.scale), otherUnit);

  String toString() => "$value $unit";
}

void main() {
  print(Length.m(2) + Length.km(1));
  print(Length.m(42).to(Length.cm));
}

这可以让你做 `` 然而,这并不需要要求指标必须是

enum
s。

如果您想定义自己的

var pentaMeter = Meter(5);
为 10^5 米,没有理由阻止您,所以我可能只是将指标设为普通类:

abstract base class Metric<M extends Metric<M>> {
  /// Name of the unit for display.
  final String name;

  /// The power of 10 of the [standardUnit] that this unit represents.
  final int scale;

  /// The standard unit of this metric.
  ///
  /// Will have a [scale] of 0.  
  M get standardUnit;

  const Metric(this.name, this.scale);
  
  /// Creates a measurement of this type.
  Measure<M> call(num value) => Measure<M>(value, this);
  
  String toString() => name;
}

/// A unit of mass or weight.
final class Weight extends Metric<Weight> {
  static const g = Weight("g", 0),
      ug = Weight("ug", -6),
      mg = Weight("mg", -3),
      kg = Weight("kg", 3);

  const Weight(super.name, super.scale);

  Weight get standardUnit => g;
}

/// A unit of length.
final class Length extends Metric<Length> {
  static const m = Length("m", 0),
      km = Length("km", 3),
      cm = Length("cm", -2),
      mm = Length("mm", -3),
      nm = Length("nm", -6);

  const Length(super.name, super.scale);
  
  Length get standardUnit => m;
}

然后以同样的方式使用它,但不关心它是否是枚举。

您可以执行

var pm = Length("pm", 5);
并将其用作长度的另一种表示法。

(请注意,尝试捕获“单位”通常会很快进入单位的组合,例如 m/s 或 kg/m2。这不是一项可能完成的任务。)

© www.soinside.com 2019 - 2024. All rights reserved.