简体   繁体   English

迁移到 Dart 空安全后出现“无法无条件调用运算符,因为接收器可以为空”错误

[英]"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety

I'm upgrading a personal package that is based on the Flutter framework.我正在升级基于 Flutter 框架的个人 package。 I noticed here in the Flutter Text widget source code that there is a null check:我在 Flutter 文本小部件源代码中注意到这里有一个 null 检查:

if (textSpan != null) {
  properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}

However, textSpan!但是, textSpan! is still using the !还在用! operator.操作员。 Shouldn't textSpan be promoted to a non-nullable type without having to use the !不应该将textSpan提升为不可为空的类型而不必使用! operator?操作员? However, trying to remove the operator gives the following error:但是,尝试删除运算符会出现以下错误:

 An expression whose value can be 'null' must be null-checked before it can be dereferenced. Try checking that the value isn't 'null' before dereferencing it.

Here is a self-contained example:这是一个独立的示例:

class MyClass {
  String? _myString;
  
  String get myString {
    if (_myString == null) {
      return '';
    }
    
    return _myString; //   <-- error here
  }
}

I get a compile-time error:我得到一个编译时错误:

Error: A value of type 'String?'错误:“字符串?”类型的值can't be returned from function 'myString' because it has a return type of 'String'.无法从 function 'myString' 返回,因为它的返回类型为 'String'。

Or if I try to get _mySting.length I get the following error:或者,如果我尝试获取_mySting.length ,则会收到以下错误:

The property 'length' can't be unconditionally accessed because the receiver can be 'null'.不能无条件访问属性“长度”,因为接收者可以为“空”。

I thought doing the null check would promote _myString to a non-nullable type.我认为执行 null 检查会将_myString提升为不可为空的类型。 Why doesn't it?为什么不呢?

My question was solved on GitHub so I'm posting an answer below.我的问题在 GitHub 上得到了解决,所以我在下面发布了一个答案。

Dart engineer Erik Ernst says on GitHub : Dart 工程师 Erik Ernst 在 GitHub 上说

Type promotion is only applicable to local variables.类型提升仅适用于局部变量。 ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. ...实例变量的提升并不合理,因为它可能被运行计算并在每次调用它时返回不同的 object 的 getter 覆盖。 Cf.参照。 dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions. dart-lang/language#1188用于讨论类似于类型提升但基于动态检查的机制,并提供一些相关讨论的链接。

So local type promotion works:所以本地类型推广有效:

  String myMethod(String? myString) {
    if (myString == null) {
      return '';
    }
    
    return myString;
  }

But instance variables don't promote.但是实例变量不会提升。 For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the !为此,您需要使用! operator:操作员:

class MyClass {
  String? _myString;
  
  String myMethod() {
    if (_myString == null) {
      return '';
    }
    
    return _myString!;
  }
}

The Error:错误:

Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:假设这是您的代码,您正在对实例变量进行 null 检查,但仍然看到错误:

class Foo {
  int? i = 0;

  double func() {
    if (i != null) return i.toDouble(); // <-- Error
    return -1;
  }
}

The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.不能无条件地调用方法“toDouble”,因为接收者可以为“null”。

The error you see in code like this is because Getters are not promoted to their non-nullable counterparts .您在这样的代码中看到的错误是因为Getter 没有提升为它们的不可为空的对应物 Let's talk about the reason why.让我们谈谈其中的原因。


Reason of the Error:错误原因:

Let's say, there's a class Bar which extends Foo and override i variable and doesn't assign it any value (keeping it null ):假设,有一个 class Bar扩展Foo并覆盖i变量并且不为其分配任何值(保留它null ):

class Bar extends Foo {
  @override
  int? i;
}

So, if you could do所以,如果你能做到

print(Bar().func() * 2);

You would have run into a runtime null error, which is why getters type promotion is prohibited.您会遇到运行时 null 错误,这就是禁止 getter 类型提升的原因。


Solutions:解决方案:

We need to cast away nullability from int?我们需要抛弃int? . . There are generally 3 ways to do this (more ways include the use of as , is , etc)通常有 3 种方法可以做到这一点(更多方法包括使用asis等)

  • Use local variable (Recommended)使用局部变量(推荐)

     double bar() { var i = this.i; // <-- Use of local variable. if (i.= null) return i;toDouble(); return -1; }
  • Use?.利用?。 with??和??

     double bar() { return i?.toDouble()?? -1; // Provide some default value. }
  • Use Bang operator (!)使用 Bang 运算符 (!)

    You should only use this solution when you're 100% sure that the variable ( i ) will never be null .只有当您 100% 确定变量 ( i ) 永远不会是null时,才应该使用此解决方案。

     double bar() { return i.;toDouble(). // <-- Bang operator in play. }

Use Ternary Operator to fix errors like this.使用三元运算符来修复这样的错误。 This is an example where headline1 can be null这是一个示例,其中标题 1 可以是 null

                    Theme
                        .of(context)
                        .textTheme
                        .headline1?.fontSize?? 32,

style: Theme.of(context).textTheme.headline5..copyWith(风格: Theme.of(context).textTheme.headline5..copyWith(

style: Theme.of(context).textTheme.headline5!.copyWith(
                        color: Colors.white

Try making the call conditional using?尝试使用? or a null safety checker - !或 null 安全检查器 - !

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Dart Null 安全:无法无条件调用方法“[]”,因为接收者可以为“null” - Dart Null Safety: The method '[]' can't be unconditionally invoked because the receiver can be 'null' 运算符 &#39;&gt;=&#39; 不能无条件调用,因为接收器可以为 &#39;null&#39;。 颤振空安全 - The operator '>=' can't be unconditionally invoked because the receiver can be 'null'. flutter null safety 不能无条件调用运算符“&lt;”,因为接收者可以为“null” - the operator '<' can't be unconditionally invoked because the receiver can be 'null' 不能无条件调用算子,因为接收者可以是 null - Operator can't be unconditionally invoked because the receiver can be null 不能无条件调用操作符“&gt;=”,因为接收者可以为“null” - The operator '>=' can't be unconditionally invoked because the receiver can be 'null' 无法无条件调用运算符“&gt;”,因为接收者可以为“null” - The operator '>' can't be unconditionally invoked because the receiver can be 'null' 错误:无法无条件调用方法“then”,因为接收者可以为“null” - ERROR: The method 'then' can't be unconditionally invoked because the receiver can be 'null 错误:无法无条件调用方法“[]”,因为接收者可以为“null” - Error:The method '[]' can't be unconditionally invoked because the receiver can be 'null' 错误:不能无条件调用“split”,因为接收者可以为“null” - Error: 'split' can't be unconditionally invoked because the receiver can be 'null' 错误:无法无条件调用方法“[]”,因为接收者可以为“null” - error: The method '[]' can't be unconditionally invoked because the receiver can be 'null'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM