Dart中的零安全

哈Ha!我提请您注意Filip Hracek的文章“宣布声音为零的安全性”的译文,并附上我的评论:



零安全性-使用空链接的安全工作。进一步在本文中,为简洁起见,并且由于术语的稳定性,将使用英文名称null,安全性null。而“零安全”的翻译则导致了完全相反的想法。

声音-在这种情况下(声音为零)可以翻译为“可靠”。

如果您有改进翻译的建议或发现错误-请以个人身份写,我们将尝试对其进行修复。
对于Dart团队来说,迈出了重要的一步,他们介绍了无效安全技术发展的技术预览。空安全避免了通常很难检测到的一整类错误,此外,它还提供了许多性能改进。目前,我们已经发布了初步的技术预览,正在等待您的反馈。



在本文中,我们将揭示Dart团队部署零安全的计划,并解释术语“声音零安全”背后的含义,以及这种方法与其他编程语言的区别。

所述版本于2020年6月10日发布。

为什么要取消安全性?



Dart是一种类型安全的语言。这意味着当您获得某种类型的变量时,编译器可以保证它属于该变量。但是,仅类型安全性不能保证变量不为null。



空错误是常见的。在GitHub上进行搜索可找到Dart代码中由空值引起的数千个报告(问题),甚至还有更多的提交试图解决这些问题。



在下面的示例中尝试发现零链接问题:



void printLengths(List<File> files) {
  for (var file in files) {
    print(file.lengthSync());
  }
}


如果使用零参数调用此函数肯定会失败,但是还有第二种情况需要考虑:



void main() {
  // Error case 1: passing a null to files.
  printLengths(null);
 
  // Error case 2: passing list of files, containing a null item.
  printLengths([File('filename1'), File('filename2'), null]);
}


空安全解决了这个问题:



图片



使用空安全,您可以更加自信地依赖代码。在运行时访问无效变量将不再有烦人的错误。编译时只有静态错误。

老实说,当前的实现仍然留有一些机会在执行时捕获空错误,以后还会更多。

声音(可靠)无效



Dart实施null安全性是合理的。如果我们使用上面的示例进行分析,则意味着Dart编译器100%确保文件数组及其中的元素不能为null。当Dart编译器分析您的代码并确定该变量不为null时,该变量将始终具有一个值:如果在调试器中检查可执行代码,您将发现在运行时根本不会归零。有些实现不是“可靠的”,在这种实现中,您仍然需要在运行时执行值的存在性检查。与其他语言不同,Dart与Swift共享实现可靠性。

, , , null safety . Swift, Kotlin Dart. .
在Dart中强大的null安全实现会带来另一个不错的结果:这意味着您的程序可以更小,更快。由于Dart确实确保变量永远不会为空,因此Dart可以优化编译结果。例如,AOT编译器可以生成更小,更快的本机代码,因为它不需要为空引用添加检查。



我们已经看到了一些非常有希望的初步结果。例如,我们在模仿基准Flutter框架中典型渲染模式的微基准测试中看到了19%的性能提升。



基本原则



在继续进行零安全性的详细设计之前,Dart团队定义了三个基本原则:



默认情况下不可为空。 / **在文档中通常可以将其视为NNBD的缩写** /如果您未明确告知Dart变量可以为空,则它将视为不可为空。我们选择此值作为默认值,因为我们发现在API中,非零值是最常见的值。/ **这可能是当前Flutter API的翻版** /



分阶段适用... 我们了解,应该有逐步逐步过渡到无效安全的可能性。实际上,您需要在同一项目中具有可空值和空安全代码。为此,我们计划提供工具来帮助代码迁移。



完全的可靠性(声音)。如上所述,Dart中的null安全是安全的。将整个项目和依赖项转换为零安全性后,您将获得所有的可靠性优势。



声明变量的安全性为空



基本语法很简单。以下是声明各种变量的示例。请注意,默认情况下使用非空变量,因此它们看起来相同,但它们的值不能为空。



// In null-safe Dart, none of these can ever be null.
var i = 42;
final b = Foo();
String m = '';


Dart将确保您绝不会为上述任何变量分配null。如果您甚至在一千行后尝试执行i = null,您将收到一个静态分析错误和红色的蠕动行-您的程序将拒绝编译。



如果希望变量为可空值,则可以使用“?” 像这样:



// These are all nullable variables.
int? j = 1;  // Can be null later.
final Foo? c = getFoo();  // Maybe the function returns null.
String? n;  // Is null at first. Can be null at any later time, too


上面列出的变量的行为与Dart当前版本中的所有变量完全相同。



'?''也可以在其他地方使用:



// In function parameters.
void boogie(int? count) {
  // It's possible that count is null.
}
// In function return values.
Foo? getFoo() {
  // Can return null instead of Foo.
}
// Also: generics, typedefs, type checks, etc.
// And any combination of the above.


但是,我再次希望您几乎永远不必使用“?”。您的绝大多数变量都是不可为空的。



使使用零安全更加容易



Dart小组正在努力使零安全性尽可能易于使用。例如,看下面的代码,它使用if测试null:



void honk(int? loudness) {
  if (loudness == null) {
    // No loudness specified, notify the developer
    // with maximum loudness.
    _playSound('error.wav', volume: 11);
    return;
  }
  // Loudness is non-null, let's just clamp it to acceptable levels.
  _playSound('honk.wav', volume: loudness.clamp(0, 11));
}


请注意,Dart非常聪明,可以意识到在传递if语句时响度不能为空。因此,Dart允许我们调用clip()方法,而不必用铃鼓跳舞。这种便利性是通过所谓的流分析来提供的:Dart解析器会像运行代码一样查看您的代码,从而自动找出有关代码的更多信息。

Flow analysis, Dart, , , . null safety, :
foo(dynamic str) {
  if (str is String) {
    // dynamic   length,   
    //      String
    print(str.length);  
  }
}


, Dart , null, :
int sign(int x) {
  // The result is non-nullable.
  int result;
  if (x >= 0) {
    result = 1;
  } else {
    result = -1;
  }
  // By this point, Dart knows the result cannot be null.
  return result;
}


- (, result = -1;), Dart , result — , .
流分析仅在函数内部起作用。如果您具有全局变量或类字段,则Dart无法保证将为其分配值。Dart无法为整个应用程序的执行流程建模。因此,如果您知道该变量将在首次调用时被初始化,但是不能在声明它时对其进行初始化,则可以使用new late关键字。



class Goo {
  late Viscosity v;
 
  Goo(Material m) {
    v = m.computeViscosity();
  }
}


请注意,尽管最初无关紧要,但无法将v归零。Dart认为您不会尝试读取v,直到为其分配了非零值并且您的代码编译没有错误为止。

— .



, . , . Dart , , , , , Kotlin .



— Swift- , , force unwrap Dart.

void main() {
  String? t;
  print(t!.length);
}


( late ‘!’) .



late , - Dart. ‘required’ . ‘@required’, .
class Temp {
  String str;
  Temp({required this.str});
  
  //   
  Temp.alt({strAtr}) : this.str = strAtr;
}




Dart团队已经进行了一年多的工作,以将零安全性带入技术预览版。这是自第二个版本发布以来最大的语言更改。但是,此更改不会破坏向后兼容性。现有代码可以调用安全性为空的代码,反之亦然。即使在完全发布之后,也可以在准备就绪时使用null安全性。您现有的代码将继续保持不变。



最近更新了Dart核心库,但没有安全性。作为向后兼容性的说明性示例,替换现有核心库的过程没有发生单个失败的测试,也没有在Dart和Flutter测试环境上运行的测试应用程序中出现错误。甚至为许多Google内部客户更新的核心库也顺利进行。我们计划重新设计所有软件包和应用程序,以在发布后使​​用null安全性,我们希望您也可以这样做。但是您可以按照自己的进度,逐批,逐个应用地进行操作。

这些话对Swift开发人员(尤其是第3版)来说是肯定的。

但是即使一切都不那么乐观,开发人员自己也说,在一个项目中结合使用空安全代码和“旧”代码时,他们不能保证其健全性类型系统。

进一步行动计划



我们计划分三个阶段逐步推出无效安全性:



  1. 技术预览。它在原始文章发布时(06/10/2020)启动,可在dev分支上找到。值得关注“立即开始”部分。它仍然非常不稳定并且可能会更改,因此我们不建议您在生产代码中使用它。但是,我们希望收到您的来信,并给我们反馈!
  2. 测试版本。空安全性将在Dart beta分支上提供,并且不再隐藏在实验性标志的后面。该实现将接近预期的最终版本。可以开始将软件包和插件迁移到pub.dev,但不建议将此更改发布为稳定版本。
  3. 稳定的版本。空安全将提供给所有人。系统将提示您将更新的软件包和插件发布为稳定版本。在此阶段也值得迁移您的应用程序。


如果一切都按计划进行,我们将在今年年底发布安全性为零的Dart稳定版本。我们会不时添加工具来帮助您迈向零安全。其中:



  • 一种迁移工具,可帮助自动执行更新现有软件包和应用程序的许多步骤;
  • pub.dev, null safety;
  • 'pub outdated' , null safety.




今天,尝试空安全性最快的方法是使用nullsafety.dartpad.dev-启用了空安全性的DartPad版本。打开“使用代码片段学习”下拉列表,找到一系列教程,涵盖了新语法和null安全的基础知识。



图片



您还可以在小型控制台应用程序中试验零安全性(我们尚未更新较大的框架,如Flutter)。首先,您需要从dev分支下载Dart SDK,然后才能下载此示例控制台应用程序。 README文件包含在启用实验性null安全功能的情况下运行应用程序的说明。该示例中的其他文件提供了运行配置,这些配置将允许在VS Code和Android Studio中进行调试。



您还可以阅读文档(以后会出现更多信息):





UPD:在评论中,我建议此链接了解零安全


我们很高兴能够在Dart中实现零安全。可靠,安全地处理空链接将成为Dart的标志,以帮助您编写最可靠,最高效的代码。我们希望您花一些时间尝试使用最新版本的null安全并将您的反馈留在我们的错误跟踪器中。有一个不错的代码!

感谢您阅读到底。翻译有点晚了,但是希望注释对材料有用,并且它还不仅仅是一对一的翻译。我想补充一点,此功能对于整个Flutter生态系统而言是非常有用的一步。我期待已在实时应用程序中使用它。同时,正如他们用外语所说的那样,请继续关注!



All Articles