【问题标题】:How to create null safe block in flutter?如何在颤振中创建空安全块?
【发布时间】:2021-06-26 10:52:59
【问题描述】:

如何在 Flutter 中进行 null 检查或创建 null 安全块?

这是一个例子:

class Dog {
  final List<String>? breeds;
  Dog(this.breeds);
}

void handleDog(Dog dog) {
    printBreeds(dog.breeds); //Error: The argument type 'List<String>?' can't be assigned to the parameter type 'List<String>'.
}

void printBreeds(List<String> breeds) {
  breeds.forEach((breed) {
    print(breed);
  });
}

如果你尝试用 if 情况包围它,你会得到同样的错误:

void handleDog(Dog dog){
  if(dog.breeds != null) {
    printBreeds(dog.breeds); //Error: The argument type 'List<String>?' can't be assigned to the parameter type 'List<String>'.
  }
}

如果您创建一个新属性然后对其进行空检查,它可以工作,但是每次您想进行空检查时都创建新属性变得很麻烦:

void handleDog(Dog dog) {
  final List<String>? breeds = dog.breeds;
  if (breeds != null) {
    printBreeds(breeds); // OK!
  }
}

有没有更好的方法来做到这一点?
像 kotlin 中的 ?.let{} 语法一样吗?

【问题讨论】:

    标签: flutter dart nullable null-check dart-null-safety


    【解决方案1】:

    是的,您将像处理这些事情一样创建一个局部变量,因为如果您不创建局部变量,那么如果有一个扩展 Dog 的类可以覆盖 breeds即使在您首先检查它之后,它也会变为可空。

    您可以尝试的另一个解决方案是在printBreeds 方法中将List&lt;String&gt; 更改为可为空。

    void handleDog(Dog dog) {
      printBreeds(dog.breeds);
    }
    
    void printBreeds(List<String>? breeds) {
      breeds?.forEach((breed) {
        print(breed);
      });
    }
    

    【讨论】:

    • 您的答案与其他答案相同,但我最喜欢它,因为您确认如果不先创建类的新实例就无法对类的成员进行空检查。我不喜欢将空检查沿链向下移动的原因是,尽早处理空检查会消除以后的任何级联检查。在我看来,也许更重要的是,一个名为 printBreeds(breeds) 的函数应该需要打印一个品种列表。如果一个州没有品种列表,它根本不应该调用 printBreeds(breeds)。你同意吗?
    • 我是第一个发布答案的人哈哈。我同意你的观点,但print 是调试所需要的,List&lt;String&gt;? 实际上意味着列表中的项目也可以是null。因此,这完全取决于您的用例。
    • 准确,你是第一个。但不准确,List?表示列表可以为空,但列表中的元素不可为空。有关更多信息,您可以滚动到本文中的“列表和集合类型”。 medium.com/flutterdevs/null-safety-in-dart-be09568ea8b8
    • 我发布了一个更接近我的问题的答案,但感谢您的意见和意见交流。
    • @JoelBroström 嗨,我不小心在List&lt;String&gt;? 中写错了?。实际上,List&lt;String?&gt; 可以有可空项目但列表不能是 nullList&lt;String&gt;? 不能有可空项目但列表可以是 null
    【解决方案2】:

    为了获得类似于 Kotlins .let{} 的东西,我创建了以下通用扩展:

    extension NullSafeBlock<T> on T? {
      void let(Function(T it) runnable) {
        final instance = this;
        if (instance != null) {
          runnable(instance);
        }
      }
    }
    

    而且可以这样使用:

    void handleDog(Dog dog) {
      dog.breeds?.let((it) => printBreeds(it));
    }
    

    let 函数中的“it”在运行时永远不会为空。

    感谢所有建议,但它们都是将 null 检查进一步移到代码执行链下方的一些变体,这不是我想要的。

    【讨论】:

    • 看起来不错!但我不太确定您是否应该在 T? 上添加扩展名
    • 为什么不呢? T 是一个泛型类,所以现在每个可为空的类都可以调用let 方法。
    • 对,你可以这样做。但是这样想。如果你说int a,你仍然可以做a.let,这没有任何意义。您可以在每种类型上使用let,这是extension 的过度使用。你应该做的是在List&lt;T&gt;上使用extension
    • 你是对的,即使它们不可为空,它也适用于所有类,但这是因为它不仅仅是一个空检查工具。它实际上创建了一个挖掘块,其中调用变量的值将在整个块存在期间保持一致。关键是在所有课程中都有它。如果您使用 kotlin,这是其实现的精确副本,如果您使用 swift,这类似于 if let xy = xyz {} 语法。写这篇文章我确实意识到 Dart 没有任何独家功能。 .apply.run.with.also 之类的东西不存在
    【解决方案3】:

    这个错误是对的//Error: The argument type 'List&lt;String&gt;?' can't be assigned to the parameter type 'List&lt;String&gt;'.

    因为空类型列表正在传递给函数,该函数表示它接受非空列表

    通过以下方式可以访问品种

    void printBreeds(List<String>? breeds) {
      breeds?.forEach((breed) {
        print(breed);
      });
    }
    

    另外,如果我们不想每次都为空操作,我们可以在调用时处理它 示例:

    class Dog {
      final List<String>? breeds;
      Dog(this.breeds);
    }
    
    void handleDog(Dog dog) {
        print("handleDog");
        printBreeds(dog.breeds!);  
    }
    // This method only called if breeds not null
    void printBreeds(List<String> breeds) {
      print("printBreeds");
      breeds.forEach((breed) {
        print(breed);
      });
    }
    
    void main() {
      var dog = Dog(null);
       handleDog(dog);
    }
    

    输出:

    打印品种

    【讨论】:

    • 我同意这个错误并且它是正确的,问题是如何去解决它。建议的方法有效,但将可空性推向链缝,就像适得其反的解决方案一样。我认为尽早处理空值检查以限制变量的潜在状态会更好。我还认为只有在您有要打印的品种列表时才应该调用名为 printBreeds(breeds) 的方法。你同意吗?
    • 检查我编辑的答案,它应该适合你
    • @Joel Broström:现在这有意义吗?
    • 感谢您抽出宝贵时间帮助我!但是,通过在printBreeds(dog.breeds!); 中“消除可空性 (!)”,我们并不能解决问题。它会编译,但如果您将 null 传递给 printBreeds,则应用程序将抛出异​​常。感叹号 (!) 并不意味着如果为 null 则不执行任何操作,而只是向编译器保证该值在运行时不会为 null。不知道你是不是在说别的,只是想指出来。 // This method only called if breeds not null 行可以用不同的方式解释。无论如何,感谢您的帮助!
    • 感谢您的帮助。这让我开始思考,我上传了自己的解决方案作为答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 2021-08-17
    • 2021-08-30
    相关资源
    最近更新 更多