为什么在Dart中使用显式的“ .cast <>()”函数而不是“ as <>”

Ric*_*son 6 dart

在我的问题中,Dart 2.X List.cast()无法构成答案,因此需要将a转换List<dynamic>为a List<String>

List<String> ls = (json['data'] as List).cast<String>().map((s) => s.toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

我从其他语言获得的经验让我首先写了这篇文章:

List<String> ls = (json['data'] as List<String>).map((s) => s.toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

请注意,这可以编译,但在Dart 2中运行时会失败。

为什么对Dart进行类型转换List需要一个功能as List).cast<String>(),而不是像Dart那样简单地使用as“类型转换运算符” as List<String>

----编辑----

我正在使用最新的Dart 2.0.0-dev.43.0,并且在as类型转换/断言中出现不一致的运行时行为。是不是该.cast<>()函数创建一个新的迭代相同的.map()?将我的代码更改为此:

List<String> ls = (json['data'] as List).map((s) => (s as String).toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

这似乎是在利用第一个强制转换List为的优势List<dynamic>。因此,.map功能参数也是dynamic

我上面的第二个示例to as List<String>可以在代码中的某些地方使用,而在其他地方则不能。请注意,IntelliJ可以正确推断上述所有示例中的类型-这是在运行时发生故障的地方。我猜这种不一致的行为是由于Dart 2.x仍在开发中。

---- 2nd编辑----

这是我的一个类构造函数中的测试用例:

Map<String, dynamic> json = { "data": ["a", "b", "c"] };

//List<String> origBroken = json["data"].map( (s) => s.toUpperCase() ).toList();

// Sometimes works - sometimes gives "Ignoring cast fail from JSArray to List<String>" at runtime!!!
List<String> wonky = (json["data"] as List<String>).map( (s) => s.toUpperCase() ).toList();
print("Wonky $wonky");

List<String> fix1 = (json["data"] as List).cast<String>().map( (s) => s.toUpperCase() ).toList();
List<String> fix2 = (json["data"] as List).map( (s) => (s as String).toUpperCase() ).toList();
List<String> explicit2 = (json["data"] as List<dynamic>).map( (dynamic s) => (s as String).toUpperCase() ).toList();

// From accepted answer of the linked question - compile error because .cast() doesn't take parameters
//   error: Too many positional arguments: 0 expected, but 1 found.
//List<String> notBroken = (json['data'] as List).cast<String>((s) => s.toUpperCase()).toList();
List<String> notBrokenFixed = (json['data'] as List<String>).cast<String>().map((String s) => s.toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

问题是作业Ignoring cast fail from JSArray to List<String>有时会给出警告wonky。当我说有时候,是因为在我对使用包含此代码的库的主应用程序进行更改时,它发生了不可预测的更改-无需更改此类甚至库。

当时我写上面的第一个编辑,wonky但没有用。我现在再次尝试过,并且可以正常工作。我没有更改此库中的任何代码-我一直在依赖于此代码库的主应用程序中进行工作。

在某些背景下,这是一个从Angular / Typescript转换而来的多库项目。这些测试用例基于我们将JSON反序列化为Dart类的处理。我们使用类构造函数初始值设定项将JSON(动态)字符串映射到各种数据结构中,例如枚举,Option <>和Either <>(来自dartz)。

我相信几个星期前开始发生运行时警告,原因是发生了重大更改:--preview-dart-2默认情况下处于打开状态。我了解此警告很快就会出错。因此,我将警告追溯到这些转换,这些转换是从JSON动态数据映射的(是的,动态数据在Dart中是一个极端的案例,但这就是dart:convert提供的内容)。

我们正在Mac上使用最新Dart 2.0.0-dev.43.0,angular 5.0.0-alpha + 8,build_runner 0.8.0,IntelliJ 2018.1并在Chrome 65.0.3325.181上运行的DDC进行开发。

----最终编辑----

当前开发版本/运行时中存在不稳定的问题。不,我没有可复制的示例。更改和重建主应用程序会导致此代码在未修改的库依赖关系中有时发出运行时警告Ignoring cast fail from JSArray to List<String>

该问题原始部分中的可疑代码(也在wonky上文中)

List<String> ls = (json['data'] as List<String>).map((s) => s.toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

将动态JSON数据转换为List<String>。类型完全受限制,Dart分析器/ IntelliJ推断sStatic type: String

有时会出现运行时警告和相关的使用答案.cast()是导致此问题的原因。目前,我相信分析器会忽略运行时警告。

Gün*_*uer 10

在Dart 2中,泛型类型得到了改进。

as ...更像是断言,如果值类型不匹配as会导致运行时异常。

cast<T>()是Dart 2中引入的一种方法,该方法Iterable实际上创建了一个新的可迭代类型Iterable<T>(或子类List<T>),并填充了原始Interable的值。

更新

您可以print('wonky: ${wonky.runtimeType}');用来查看实际类型是什么。

如果类型符合您的要求,则可以使用as它来与分析仪进行通讯,以确保可以安全地使用此类型。

如果类型不匹配(例如因为List而不是)List<String>,则可以使用.cast<String>()实际将其设置为List<String>

List<String> notBroken = (json['data'] as List).cast<String>((s) => s.toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

在这里,您似乎尝试将其cast用于投射和映射,但这是无效的。 map()可以同时做

List<String> notBroken = (json['data'] as List).map<String>((s) => s.toUpperCase()).toList();
Run Code Online (Sandbox Code Playgroud)

  • 另外,请注意,根据有效飞镖指南,“当附近的操作(如List &lt;T&gt; .from()”将可用时,请不要使用“ cast()”)。那是因为`cast()`方法返回一个惰性集合,该集合检查每个操作的元素类型。如果只对几个元素执行几个操作,那么懒惰就可以了。但是在许多情况下,延迟验证和包装的开销超过了好处。〜来源:https://www.dartlang.org/guides/language/effective-dart/usage#dont-use-cast-when-a-nearby-operation-will-do (2认同)