我发现自己面临着 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;
}
作为这个概念的新手,有人可以提供见解和指导吗?先谢谢你了
对于您的直接问题,
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。这不是一项可能完成的任务。)