Navigator 上 then 方法的语法问题

Syntax issue with then method on Navigator

我有以下代码片段:

_openEditListingDialog(Listing listing,
    Function(Listing) onSubmittedCallback) async {
      Navigator
      .of(context)
      .push(
        new MaterialPageRoute<Listing>(
          builder: (BuildContext context) {
            return new ListingDialog.edit(listing);
          },
          fullscreenDialog: true,
        ),
      )
      .then((Listing newEntry) {
        if (newEntry != null) {
          newEntry.id = listing.id;
          onSubmittedCallback(newEntry);
        }
      });
  }

VSCode 抱怨 .then 行出现以下错误:

[dart] The argument type '(Listing) -> Null' can't be assigned to the parameter type '(Object) -> FutureOr<Null>'.

这是什么意思,我该如何更正?我是 dart 和 flutter 的新手,像这样的错误消息对我来说很神秘。我的代码基于这个例子:https://github.com/MSzalek-Mobile/weight_tracker/blob/v0.4.1/lib/home_page.dart.

你传递一个函数

Function(Listing) onSubmittedCallback) async {
  // no return here
});

这意味着 Dart 推断 return 类型 Null

我想改成

FutureOr<Null> Function(Listing) onSubmittedCallback) async =>

并在末尾(代码的最后一行)删除 } 应该可以修复它。

如果你想保留函数体{...}使用

    FutureOr<Null> Function(Listing) onSubmittedCallback) async {
      await Navigator
      .of(context)
      ...

TBH 我不确定为什么 VS Code 将其标记为您的错误 - 我没有发现任何实质性错误,我的 VS Code 或 IntelliJ 也没有。我粘贴了你的代码,在添加了一个清单 class 之后,我一点问题都没有(为了记录,如果你粘贴了足够多的代码,当你遇到问题时,有人可以 运行 解决问题他们更容易帮助你)。

在这种特殊情况下,错误的行号可能会很有帮助。

也许确保你的 VS Code 和 Flutter 是最新的(我正在使用已经更新到 dart 2.0 的 Master channel/branch 所以它可能是它的一部分......)。

您可以尝试几件事。首先,您的 push 方法似乎没有选择正确的类型 - 我很确定您看到的错误是在它期望的 .then(... 和 Object 处告诉它是一个清单。您可以将 .push 更改为 .push<Listing> 以强制其成为 return 列表。

接下来,我实际上并不熟悉你用 Function(Listing) 做什么。我不认为这是正确的飞镖,或者至少不再是。我认为推荐的做法是 typedef-ing 一个具有正确参数类型的方法,即 typedef void ListingCallback(Listing listing); 然后使用它作为参数,如果你要使用回调(见后面的回答一个可以说是更好的选择)。

您做错的另一件事是 mis-using async,很多人一开始似乎都在做 dart/flutter。如果你在方法签名中使用 async,你不应该为 futures 使用 .then,而应该使用 await。请参阅有效飞镖的 here and this 部分。我已经 re-written 你的代码可以正确地做到这一点:

//outside class somewhere
typedef void ListingCallback(Listing listing);

...

  _openEditListingDialog(
      Listing listing, ListingCallback onSubmittedCallback) async {
    Listing newEntry = await Navigator.of(context).push<Listing>(
          new MaterialPageRoute<Listing>(
            builder: (BuildContext context) {
              return new ListingDialog.edit(listing);
            },
            fullscreenDialog: true,
          ),
        );

    if (newEntry != null) {
      newEntry.id = listing.id;
      onSubmittedCallback(newEntry);
    }
  }

请注意,这也会删除导致您出现问题的整个函数。

此外,您可以只使用 futures 并删除方法签名中的 async,但是您将必须确保实际 return 一个 future。

最后,您可以(应该)可能 returning Future 而不是传递回调。

  Future<Listing> _openEditListingDialog(Listing listing) async {
    Listing newEntry = await Navigator.of(context).push<Listing>(
          new MaterialPageRoute<Listing>(
            builder: (BuildContext context) {
              return new ListingDialog.edit(listing);
            },
            fullscreenDialog: true,
          ),
        );

    if (newEntry != null) {
      newEntry.id = listing.id;
    }

    return newEntry;
  }