【问题标题】:Why we should avoid as in dart为什么我们应该避免像飞镖一样
【发布时间】:2020-03-24 19:58:10
【问题描述】:
从 dart lint 规则我不明白我们为什么要avoid as
如果您知道类型是正确的,请使用断言或分配给更多
窄类型变量(这避免了发布模式下的类型检查;
as 不会在发布模式下编译出来)。如果你不知道是否
类型是否正确,使用 is 检查(这样可以避免as 的异常
提高)。
如果使用,在运行时会有什么影响:
(pm as Person).firstName = 'Seth';
代替:
Person person = pm;
person.firstName = 'Seth';
为什么会有这样的好处:
这避免了发布模式下的类型检查; as 在发布模式下没有编译出来
只是性能改进还是如果类型错误会避免崩溃?
【问题讨论】:
标签:
dart
compilation
runtime
lint
【解决方案1】:
目前,如果代码完全有效,这两种方法的 Dart 语义没有区别。
如果pm 的类型是Person 的超类型,则赋值会附加一个隐式as Person 强制转换。这就是 Dart 当前添加到一些原本不安全的所谓“隐式向下转换”。如果它的类型是Person 的子类型,那么它可以在没有强制转换的情况下分配,并且不会添加强制转换。如果两者都不是,则根本不可赋值,代码是编译时错误。
一些 JavaScript 编译器可能会在其“生产模式”中省略一些检查。这不符合 Dart 语义,它是一种“不安全的优化”,这就是 lint 文本所暗示的。
如果您的代码本机运行,而不是在 JavaScript 上运行,则不适用,并且 lint 文本具有误导性。
生产模式编译器也可以轻松省略 as 强制转换。根据文本,它目前没有(或在撰写文本时没有)。
这完全是一个性能优化。它省略了强制转换,因为它假设它会成功。如果类型错误,这将“避免崩溃”,但是当以下代码假定类型实际上是正确的时,代码可能很快就会崩溃。这不是避免崩溃的方法,而是降低本来不会崩溃的代码开销的方法。
这是 Dart 的 当前 版本。 Dart 团队正在积极致力于引入可靠的不可空类型,其中一部分是完全消除隐式向下转换。发生这种情况时,代码Person person = pm; 将失效。你必须明确写Person person = pm as Person;(没有隐式向下转换),或者你更可能只写var person = pm as Person;。
当您知道它会成功时,您仍然应该只有我们as。您可以出于多种原因知道这一点,可能是因为某些类不变量确保一个属性具有特定类型,而另一个属性具有特定值。如果你这样做了,那么不安全地优化生产模式编译器仍然会生成功能代码。
如果你不知道,你应该先测试。 if (pm is Person) { .. pm is Person here .. } 测试允许您使用 pm local 变量在它被测试的类型,至少如果编译器可以确定它的值不会改变。