Dart 常量构造函数与静态最终规范值
根据Dart 常量构造函数与静态最终规范值,dart,Dart,根据constDart中的表达式是“深度不变”的,这意味着内部的任何内容都无法更改,因此整个表达式将始终表示相同的内容。这对编译器很有用,因为它可以一次生成整个对象图,并在每次出现此类表达式时重新使用它,而且程序员知道此类表达式(即使是深度嵌套的表达式)仍然遵循值语义,不会在我背后做任何事,这一点很有用 我正在使用编译器的这些优化来使用结构良好的对象模型(例如,而不是用位向量手工编码),并且仍然可以获得良好的性能。由于我们也可以通过使用static final习惯用法将一些值设置为运行时常量来“
const
Dart中的表达式是“深度不变”的,这意味着内部的任何内容都无法更改,因此整个表达式将始终表示相同的内容。这对编译器很有用,因为它可以一次生成整个对象图,并在每次出现此类表达式时重新使用它,而且程序员知道此类表达式(即使是深度嵌套的表达式)仍然遵循值语义,不会在我背后做任何事,这一点很有用
我正在使用编译器的这些优化来使用结构良好的对象模型(例如,而不是用位向量手工编码),并且仍然可以获得良好的性能。由于我们也可以通过使用static final
习惯用法将一些值设置为运行时常量来“显式散列”,从而获得其中的一些好处,因此出现了一个问题:在哪种情况下使用这两种样式中的哪一种是好的样式
考虑以下示例:
enum ShaftType { RING, SUN, CARRIER }
class Shaft {
final int index;
final ShaftType type;
Shaft(this.type, this.index) {
assert((type == ShaftType.CARRIER) == (index == null));
}
const Shaft.CARRIER()
: type = ShaftType.CARRIER,
index = null;
const Shaft.RING(this.index) : type = ShaftType.RING;
const Shaft.SUN(this.index) : type = ShaftType.SUN;
}
class GearPath {
final Shaft input, output, fixed;
GearPath({this.input, this.output, this.fixed}) {
// input and output must be set
assert(null != input && null != output);
// fixed shaft can't be anything else
assert(fixed != input && fixed != output);
}
GearPath.carrierToFirstRingFixedSun(int i)
: input = const Shaft.CARRIER(),
output = const Shaft.RING(0),
fixed = new Shaft.SUN(i) {}
static final singleFixedSunUp = new GearPath(
input: const Shaft.CARRIER(),
output: const Shaft.RING(0),
fixed: const Shaft.SUN(0),
);
static final directDrive = new GearPath(
input: const Shaft.CARRIER(),
output: const Shaft.CARRIER(),
fixed: null,
);
// ...
}
我不能使主轴(..)
和齿轮级(..)
构造函数常数
,因为我想检查一些约束,但我可以提供符合这些约束(至少部分)的特殊情况构造函数(例如轴.SUN(inti)
,轴.CARRIER()
)通过设计并为用户提供这些通用值的易读缩写
另一方面,当一个常量
构造函数没有参数时,我也可以像使用GearStage.directDrive
一样,将其作为静态final
成员编写。如果所有用户都引用这个静态成员,而不是再次重新创建值,那么我们还可以获得共享内存和快速比较(引用同一对象)的好处。我不能将此定义的右侧声明为const,因为它使用了非const构造函数,但开发人员可以从上下文中看到,这确实是一个常量值,而不是隐藏在静态字段中的全局可变单例。所以在实际应用中,它应该和常量构造函数一样好,对吗
由于我还没有发现这是一种最佳实践,我的问题很简单,这是否真的是一种很好的方法,可以在const
构造函数和static final
命名值实例之间进行组合和权衡
最后,我想知道是否有一种方法可以将GearPath.carrierToFirstRingFixedSun(inti)
也声明为常量构造函数?目前我不能,因为const Shaft.SUN(I)
抱怨I
不是常数
()Dart 2将允许您在常量构造函数中拥有断言(只要您的条件可以作为常量表达式计算)。 然后你就可以写:
GearPath({this.input,this.output,this.fixed})
://必须设置输入和输出
断言(null!=输入和null!=输出),
//固定轴不能是其他任何东西
断言(!等同(固定,输入)和&!等同(固定,输出));
在此之前,您不能同时拥有验证和常量表达式
您仍然无法使GearPath.carrierTofIstringFixedSun(int i)
const,因为它i
不是常数。const Shaft.SUN(i)
仍然不是有效的常量表达式,即使i
是常量构造函数的参数。每个const构造函数(…)
调用仍然必须只创建一个对象,即使它发生在另一个const构造函数的初始值设定项列表中
作为经验法则,您应该考虑将值暴露为const而不是最终是否是要提交的。当您将变量设置为常量时,这意味着其他人可以在另一个常量表达式中使用该值,然后将变量更改为final将是一个突破性的更改。说某事是常数是一种承诺,你应该慎重选择,而不仅仅是因为你可以。因此,考虑变量的用例。如果您没有看到它在其他常量表达式中使用,那么就将其设置为final