为什么显式的“.cast<>()"Dart 中的函数而不是“as <>" [英] Why an explicit ".cast<>()" function in Dart instead of "as <>"

查看:34
本文介绍了为什么显式的“.cast<>()"Dart 中的函数而不是“as <>"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的问题 Dart 2.X List.cast() 中not compose 答案需要将 List 转换为 List 如下:

In my question Dart 2.X List.cast() does not compose the answer requires converting a List<dynamic> to a List<String> as such:

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

我使用其他语言的经验让我先写了这个:

My experience from other languages had me write this first:

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

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

Note that this compiles but fails at runtime in Dart 2.

为什么 Dart 对 List 的类型转换需要函数 as List).cast() 而不是简单地使用 Dart ascode> 类型转换运算符",例如 as List?

Why does Dart typecasting for a List require a function as List).cast<String>() as opposed to simply using the Dart as "typecast operator" such as as List<String>?

---- 编辑----

---- Edit ----

我正在使用最新的 Dart 2.0.0-dev.43.0,并且使用 as 类型转换/断言获得不一致的运行时行为..cast<>() 函数创建一个新的可迭代对象不是与 .map() 一样吗?将我的代码更改为此有效:

I am using the most recent Dart 2.0.0-dev.43.0 and get inconsistent runtime behavior with as typecasts/assertions. Isn't the .cast<>() function creating a new iterable the same as a .map()? Changing my code to this works:

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

这似乎利用了对 List 的第一个转换是 List.因此.map函数参数也是一个dynamic.

This seems to take advantage that the first cast to List is a List<dynamic>. Thus the .map function parameter is also a dynamic.

我上面使用 to as List 的第二个示例在我们代码的某些地方有效,但在其他地方无效.请注意,IntelliJ 正确推断了上述所有示例中的类型 - 这是发生故障的运行时.我猜测不一致的行为是由于 Dart 2.x 仍在开发中.

My second example above with to as List<String> works in some places in our code but not others. Note that IntelliJ correctly infers the types in all of the above examples - it's the runtime where the failure happens. I'm guessing that the inconsistent behavior is due to Dart 2.x being still in development.

---- 第二次编辑----

---- 2nd Edit ----

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

Here are my test cases that I have in one of my class constructors:

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();

问题是警告 Ignoring cast fail from JSArray to List 有时由 wonky 赋值给出.当我说有时是因为当我对使用包含此代码的库的主应用程序进行更改时,它会发生不可预测的变化 - 没有对此类甚至库进行更改.

The problem is the warning Ignoring cast fail from JSArray to List<String> sometimes given by the wonky assignment. When I say sometimes it's because it changes unpredictably as I make changes to the main application that uses the library that contains this code - without making changes to this class or even the library.

在我编写上面的第一个编辑时,wonky 不起作用.我现在又试了一次,它正在工作.我没有更改这个库中的任何代码——我一直在主应用程序中工作,它依赖于这个代码的库.

At the time I wrote the first edit above, wonky wasn't working. I just tried it again now and it's working. I have not changed any code in this library - I have been working in the main application which has a dependency on this code's library.

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

Some background, this is a multi-library project being converted from Angular/Typescript. These test cases are based on the processing we do to deserialize JSON into Dart classes. We map JSON (dynamic) strings into various data structures such as enums, Option<> and Either<> (from dartz) using class constructor initializers.

几周前,运行时警告开始发生,我相信是因为 Breaking更改:--preview-dart-2 默认开启.我知道这个警告很快就会成为一个错误.所以我将警告追溯到这些从 JSON 动态数据映射的转换(是的,动态数据是 Dart 中的一个边缘情况,但它是 dart:convert 提供的).

A couple weeks ago the runtime warning started happening I believe because of Breaking Change: --preview-dart-2 turned on by default. I understand that this warning will soon be an error. So I traced the warning back to these conversions that map from JSON dynamic data (Yes, dynamic data is an edge case in Dart but it's what dart:convert provides).

我们正在 Mac 上使用 DDC 和最新的 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 上运行.

We are developing on Mac using DDC with the most recent Dart 2.0.0-dev.43.0, angular 5.0.0-alpha+8, build_runner 0.8.0, IntelliJ 2018.1 and running on Chrome 65.0.3325.181.

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

---- Final Edit ----

导致此问题的当前开发构建/运行时存在不稳定性.不,我没有可重复的示例.更改和重建我们的主应用程序将导致未修改的库依赖项中的此代码有时会发出运行时警告Ignoring cast failure from JSArray to List.

There is an instability in the current development build/runtime that is behind this issue. No, I don't have a reproducible example. Changing and rebuilding our main app will cause this code in an unmodified library dependency to sometimes give the runtime warning Ignoring cast fail from JSArray to List<String>.

来自这个问题原始部分的可疑代码(也是上面的wonky)

The suspect code from the original part of this question (also wonky above)

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

将动态 JSON 数据转换为 List.类型是完全约束的,Dart 分析器/IntelliJ 将 s 推断为 Static type: String.

casts the dynamic JSON data to a List<String>. The types are fully constrained and the Dart analyzer/IntelliJ infers s to be Static type: String.

有时出现的运行时警告和使用 .cast() 的相关答案是导致这个问题的原因.这时候我会相信分析器并忽略运行时警告.

The runtime warning that sometimes occurs and related answers to use .cast() is what led to this question. At this time I'll believe the analyzer and ignore the runtime warning.

推荐答案

在 Dart 2 中,泛型类型被具体化.

In Dart 2 generic types are reified.

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

as ... is more like an assertion, if the values type doesn't match as causes a runtime exception.

cast() 是 Dart 2 在 Iterable 上引入的一个方法,它实际上创建了一个 Iterable 类型的新迭代>(或在您的情况下为子类 List)填充了原始可交互的值.

cast<T>() is a method introduced in Dart 2 on Iterable that actually creates a new iterable of type Iterable<T> (or in your case the subclass List<T>) filled with the values of the original interable.

更新

您可以使用print('wonky: ${wonky.runtimeType}');查看实际类型.

You can use print('wonky: ${wonky.runtimeType}'); to see what the actual type is.

如果类型符合您的要求,您可以使用 as 将其传达给分析器,表明假设此类型是安全的.

If the type matches your requirement, you can use as to communicate it to the analyzer that it's safe to assume this type.

如果类型不匹配,例如因为它是 List 而不是 List,那么您可以使用 .cast;() 实际上使它成为 List.

If the type doesn't match, for example because it is List instead of List<String>, then you can use .cast<String>() to actually make it a List<String>.

List<String> broken = (json['data'] as List)
  .cast<String>((s) => s.toUpperCase()).toList();

这里您似乎尝试使用 cast 进行转换和映射,但这是无效的.map() 两者都可以

Here you seem to try to use cast for casting and mapping, but that is not valid. map() can do both though

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

这篇关于为什么显式的“.cast&lt;&gt;()"Dart 中的函数而不是“as &lt;&gt;"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆