dart 无法无条件调用方法“validate”,因为接收者可以为“null”

Raq*_*cio 2 dart flutter

我正在研究flutter,我遇到了一个问题,但我无法解决它。我试图根据一些代码制作一个计算器,并出现此错误

无法无条件调用方法“validate”,因为接收者可能为“null”。尝试使调用成为有条件的(使用“?.”)或向目标添加空检查(“!”)。

这是代码

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(home: Home()));
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  TextEditingController pesoController = TextEditingController();
  TextEditingController alturaController = TextEditingController();
  String _info = "Informe seus dados";
  GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  void _reset() {
    setState(() {
      pesoController.text = "";
      alturaController.text = "";
      _info = "Informe seus dados";
    });
  }

  void _calculate() {
    double peso = double.parse(pesoController.text);
    double altura = double.parse(alturaController.text) / 100;
    double imc = peso / (altura * altura);

    setState(() {
      if (imc < 18.6) {
        _info = "Abaixo do Peso (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 18.6 && imc <= 24.9) {
        _info = "Peso Ideal (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 24.9 && imc <= 29.9) {
        _info = "Levemente acima do peso (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 24.9 && imc <= 34.9) {
        _info = "Obesidade Grau I (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 34.9 && imc <= 39.9) {
        _info = "Obesidade Grau II (${imc.toStringAsPrecision(2)})";
      } else if (imc >= 40) {
        _info = "Obesidade Grau III (${imc.toStringAsPrecision(2)})";
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Calculador IMC"),
        centerTitle: true,
        backgroundColor: Colors.deepPurple,
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.refresh),
            onPressed: _reset,
          )
        ],
      ),
      backgroundColor: Colors.white,
      body: SingleChildScrollView(
        padding: EdgeInsets.all(20),
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Icon(Icons.person, size: 120, color: Colors.deepPurple),
              TextFormField(
                keyboardType: TextInputType.number,
                decoration: InputDecoration(
                    labelText: "Peso (KG)",
                    labelStyle: TextStyle(color: Colors.deepPurple)),
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.deepPurple, fontSize: 25),
                controller: pesoController,
                validator: (value) {
                  if (value!.isEmpty) {
                    return "Informe seu peso!";
                  }
                },
              ),
              TextFormField(
                keyboardType: TextInputType.number,
                decoration: InputDecoration(
                    labelText: "Altura (CM)",
                    labelStyle: TextStyle(color: Colors.deepPurple)),
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.deepPurple, fontSize: 25),
                controller: alturaController,
                validator: (value) {
                  if (value!.isEmpty) {
                    return "Informe sua altura!";
                  }
                },
              ),
              Padding(
                  padding: EdgeInsets.fromLTRB(0.0, 15, 0.0, 15),
                  child: Container(
                    height: 50,
                    child: RaisedButton(
                      onPressed: () {
                        if (_formKey.currentState.validate()) {
                          _calculate();
                        }
                      },
                      child: Text(
                        "Calcular",
                        style: TextStyle(color: Colors.white, fontSize: 25),
                      ),
                      color: Colors.deepPurple,
                    ),
                  )),
              Text(_info,
                  textAlign: TextAlign.center,
                  style: TextStyle(color: Colors.deepPurple, fontSize: 25))
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Pic*_*hio 17

解释如下。

让我们考虑一下适用于此的行:

_formKey.currentState.validate()
Run Code Online (Sandbox Code Playgroud)

消息

无法无条件调用方法“validate”,因为接收者可能为“null”。尝试使调用成为有条件的(使用“?.”)或向目标添加空检查(“!”)。

意味着在某些情况下,“validate”之前的属性(即“currentState”)可能为 null(https://dart.dev/null-safety了解更多信息)。

在它实际上为 null 的情况下,您不能调用“validate”方法,因为 null 没有“validate”方法。换句话说,自从这样做

null.validate()
Run Code Online (Sandbox Code Playgroud)

是不行的,在某个东西上调用“validate”方法(或者只能是,如果您激活了 null 安全) null 也是不行的:dart 试图告诉您必须处理这种情况的空值。在空安全之前,您可以编写该代码,并且可以在这种情况的运行时找到。

事实上,在运行时“_formKey.currentState”可能是您所期望的一个对象,但在某些特定情况下它也可能为 null。您必须决定如何处理:您是否 100% 确定在这种情况下“_formKey.currentState”不能为空?或者你不确定?

此时你有两个选择:

  1. 使用“空断言运算符”(!.):例如,手动告诉编译器调用“validate”方法此时是完全安全的,因为您已经确定即使该变量在某些情况下理论上可以为空,您已经检查过了,并且该特定情况是 100% 安全的。换句话说,在代码的特定点上它永远不会为空。请注意,如果你错了,它将在运行时抛出错误(对空值使用空检查运算符)。
    _formKey.currentState!.validate();
Run Code Online (Sandbox Code Playgroud)
  1. 使用“null 感知运算符”(?.):您不确定在这种情况下 currentState 是否可以为 null。你告诉你的编译器在幕后写这个:
    if(_formKey.currentState != null) {
       _formKey.currentState.validate();
    }
Run Code Online (Sandbox Code Playgroud)


小智 7

只需添加“!” 或者 '?' 在 .validate() 之前。所以改变这一行:

if (_formKey.currentState.validate()) {
Run Code Online (Sandbox Code Playgroud)

到:

if (_formKey.currentState!.validate()) {
Run Code Online (Sandbox Code Playgroud)

这是因为 dart 2.0 添加了空安全运算符。您可以在此链接中阅读更详细的内容:https://dart.dev/null-safety