为什么这个变量是 'String?' 类型,即使删除了任何空检查?

Why this variable is type 'String?' even when any null check was removed?

我想用 dart 包存储一个令牌 shared_preferences(仅用于测试目的),并进行 dart 改造以发出 http 请求,但是当使用 _testToken.setString(key, token) 时, dart 在令牌处弹出错误 (_testToken.setString(key, token)): The argument type 'String?' can't be assigned to the参数类型 'String',我从改造令牌响应中删除了任何 null safe 以寻找解决方案,但我遇到了同样的错误,除此之外,dart 还显示另一个错误,说我应该添加 null safe到令牌响应,如果我用它来存储 shared_preferences.

将会出错

这里是改装响应文件:

@JsonSerializable()
class ResponseData {

  @JsonKey(name: 'status')
  final int? statusCode;

  Map<String, String> data;

  ResponseData({this.data, this.statusCode}); // Here I had required on data and removed it

  factory ResponseData.fromJson(Map<String, dynamic> json) => _$ResponseDataFromJson(json);
  Map<String, dynamic> toJson() => _$ResponseDataToJson(this);

}

主要改造 http 文件:

part 'rest_api_service.g.dart';

@RestApi(baseUrl: "http://192.168.1.120/api/mobile")
abstract class RestClient {

  factory RestClient(Dio dio, {String? baseUrl}) = _RestClient;

  @Headers(<String, dynamic> {
    "Cache-Control" : "max-age=0",
    "Data-Agent" : "EMMappV2",
    "content-type" : "multipart/form-data",
    "accept" : "application/json"
  })

  @POST("/login")
  Future<ResponseData> loginUser( // here using the ResponseData
      @Field("email") String email,
      @Field("password") String password,
      @Field("device_name") String deviceName
      );

}

AuthProvider文件(仅展示功能):

  await client.loginUser(email, password, deviceName).then(
          (value) => {
            print(value.data["token"]),
            variabl = value.data["token"],
            // _storage.write(key: "token", value: value.data["token"]),  Does not work on web version
            _testToken.setString('token', value.data["token"]), // here the call with the error

            if (value.statusCode == 200 ) {
              RouteKey.navigatorKey.currentState!.pushNamed(loginRoute)
            }
          }); 

问题是 Dart 静态分析无法确定您在 value.data 映射中有一个有效的 "token" 键,其值不可为空 value.data["token"]

解决方法是使用 ! bang 运算符将此值标记为不可为 null。

_testToken.setString('token', value.data["token"]!),

The Map index operator is nullable

This isn’t really a change, but more a thing to know. The index [] operator on the Map class returns null if the key isn’t present. This implies that the return type of that operator must be nullable: V? instead of V

这是因为 data['value'] 不能保证实际 return 映射中的值(键不存在,并且由于 Map/HashMap 接口,抛出不是一个好方法选项)所以即使您知道所有值都不为空,您也不知道在运行时哪些键 return 不是空值。

检查 Map class

中的运算符

如果您真的想检查您的数据不可为空并将其视为您的模型应该将所有键解码为不可为空的参数

@JsonSerializable()
class ResponseData {

  @JsonKey(name: 'status')
  final int? statusCode;

  final String token;
  //final String userName; //and other stuff inside your map

  ResponseData({this.token, this.userName, this.statusCode}); // Here I had required on data and removed it

  factory ResponseData.fromJson(Map<String, dynamic> json) => _$ResponseDataFromJson(json);
  Map<String, dynamic> toJson() => _$ResponseDataToJson(this);

}

现在您的 Response 数据实际上会将所有参数都保存为非空并且 Dart 不会为您检查它(除非地图实际上没有这些值,然后 fromJson 将抛出并且您将明白为什么 Map 实际上不是一种检查非空的推荐方法)