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