Flutter Future <dynamic>与Future <String>子类型错误?

Cha*_* Jr 0 asynchronous future dynamic dart flutter

我刚刚更新了Flutter,并成功从中下载了我的原始项目git。现在我收到一个奇怪的Future错误。我可以在github上在线看到它,但是没有关于如何修复的明确答案。该项目甚至没有加载。它从我的main.dart文件中读取Future语句并返回此...

[VERBOSE-2:dart_error.cc(16)]未处理的异常:类型'Future dynamic'不是类型'Future String'的子类型,其中
Future来自dart:async
Future来自dart:async
字符串来自dart:core

***不确定错误在哪里。我的飞镖分析说“仅等待期货”。这是我的小部件开始构建之前运行的期货代码...

Future<Null> getData() async{
    FirebaseUser user = await FirebaseAuth.instance.currentUser;
    user = FirebaseAuth.instance.currentUser;
    var userid = user.uid;
    fb.child('users/${userid}').onValue.listen((Event event) {
      if (event.snapshot.value != null) {
        name = event.snapshot.value['displayName'];
        image = event.snapshot.value['image'];
      } else {
        name = "User";
      }
    });
  }
Run Code Online (Sandbox Code Playgroud)

Cha*_*ler 5

好。我想我明白了。

Dart 1.0是一种软类型语言,所以类似

main() async {  
  print(await getData()); 
}

Future<Null> getDatare() async{return "a";} 
Run Code Online (Sandbox Code Playgroud)

会打印“ a”

事实是Dart 2.0是一种类型化的语言,因此Future实际上具有含义。简而言之,这里发生的是Future成为FutureNull,并且您无法从FutureNull获取字符串(因为它仅包含Null)。

其实,这曾经让我有点难过[1],但是如果您考虑一下,那是有道理的。看下面的代码:

List<dynamic> l = ["a", "b", "c", "d"];
List<String> d = l;
Run Code Online (Sandbox Code Playgroud)

甚至更多

List<int> l = [1,2,3,4];
List<double> d = l;
Run Code Online (Sandbox Code Playgroud)

将在Flutter中崩溃。为什么?因为想想这里发生了什么:

什么是“ l”?

----------------------
| int | int | int | int |
----------------------
Run Code Online (Sandbox Code Playgroud)

什么是“ d”?

---------------------------------------------
| double | double | double | double |
---------------------------------------------
Run Code Online (Sandbox Code Playgroud)

那么,如何在“ l”和“ d”之间转换?

您必须创建一个新的双精度列表,然后将值复制到l中,将其转换为双精度,然后将其存储在“ d”中。

但这不仅适用于列表。它适用于所有泛型。

当你碰到这样的A<B>,这是一个完全不同的类型A<C>,你可以不投简单地从一个转换为另一个,并出于同样的原因:

采取以下代码:

class Box<T> {
  T a;
  Box(T v) {
    a=v;
  }
  T getVal() {
    return a;
  }
  }
Run Code Online (Sandbox Code Playgroud)

现在将Box转换为Box。没道理吧?我可以做以下事情吗?

Box<int> i = new Box(5);
Box<String> s= new Box("a");
i + (s as Box<int>)
Run Code Online (Sandbox Code Playgroud)

因此,这里真正发生的是Box变成BoxInt,而Box变成BoxString(通过编译器查找/将标识符“ T”替换为“ int”或将“ T”替换为“ String”)。

因此,您在这里遇到了同样的事情:您必须从未来拆箱价值,然后再使用它。在您的情况下(实际上,您的情况还有另一个问题-您什么也不返回),您可能想要一个Future,然后await该Future并获取一个String。


[1]。它是怎么咬我的?来自Kotlin(或任何其他JVM语言),我习惯于执行以下操作:

List<A> a = ...;
List<B> b = a;
Run Code Online (Sandbox Code Playgroud)

没问题。为什么?因为JVM没有真正的泛型。它所做的被称为“类型擦除”,实际上发生了什么:

List<Object> a = ...;
List<Object> b = a;
Run Code Online (Sandbox Code Playgroud)

好吧,这显然是可行的,因为所有人都List拥有一个指向对象的指针,该指针是在运行时确定的。

那是因为Java 1.0(与Dart不同)从未使用过泛型,并且使用了泛型,因此为了向后兼容,它们使泛型的类型安全性降低了。

因此Dart(或C ++或Rust或Go数组)将泛型视为单态,而Java将它们视为多态代码(将“ T”作为指针)。