среда, 7 апреля 2021 г.

Nullability

//Sound Null Safety >= Dart 2.12!
void main() {

  //old - need check for null
  const pers = {
    'name': 'Tom',
  };
  if (pers['age'] != null) {
    print(pers['age']);
  }

  //Not Nullable and Nullable types (int, int?, ..)
  //all is "Object?"!!! (root class)
  int x1; //int - not nullable type by default (cannot be null)
  //print(x1); //error!!! - must be assigned before used!!!
  int? x2 = null; //int? - nullable type (can be null)
  int? x3; //null by default
  print(x3); //it is okay - null

  //new Flow Analysis
  if (5 > 3) { //if-else condition
    x1 = 1; //dart check - x1 has value
  } else {
    x1 = 2; //dart check - x1 has value
  }
  //x1 = (5 > 3) ? 1 : 2; //ternary operator
  print(x1); //dart check - x1 has value

  //Promotion
  x2 = 2;
  if (x2 != null) { //if null-check
    //dart check - x2 has value
    print(x2); //x2 promote! to non nullable
  }

  //Null-aware operators
  //Assertion operator (postfix !) make non-nullable
  //equivalent to casting from Object? to Object
  int x = 42;
  int? mayBe;
  if(x > 0){
    mayBe = x;
  }
  //int value = mayBe; //error!
  //int? value0 = mayBe as int; //OK! - casting from int? to int
  //assert(mayBe! != null); //assert null-check
  int? value1 = mayBe!; //Ok! - assertion (!) operator
  print(value1); //42

  //null-check - ternary operator
  mayBe = null;
  var val = (mayBe == null) ? 0 : mayBe;
  print(val); //0

  //if-null operator (??)
  mayBe = null;
  var val1 = mayBe ?? 0; //if mayBe == null, use 0 for val1
  print(val1); //0

  //null-conditional assign operator (??=)
  mayBe = null;
  //mayBe = mayBe ?? 0; // x = x + 1 >>> x += 1 >>> ??=
  mayBe ??= 0; //if mayBe == null, assign 0 to it.
  print(mayBe);

  //Null Safety with collections
  var cities1 = <String?>['London', 'Paris', null]; //items can be null
  print(cities1);
  for (var city in cities1){
    if (city != null) { //city promote to non nullable
      print(city.toUpperCase());
    }
  }
  //null-conditional access operator (?.)
  for (var city in cities1){
    print(city?.toUpperCase()); //if city != null call method
  }

  //null-conditional index operator (?[])
  List<int>? numbers = [1, 2, 3]; //list can be null
  numbers = null;
  var item = numbers?[0]; //if numbers is not null, get item by index
  print('item: $item'); //null

  //null-conditional spread operator (...?)
  var numbers2 = [...?numbers];
  print(numbers2);

  //Nullable class properties, methods and objects
  final u1 = User(name: 'Tom');
  //u1.phone = '02';
  assert(u1.phone == null);
  print(u1.phone); //null
  //u1.phone ??= 'no phone';
  print('u1: ${u1.phone?.length ?? 'no phone'}'); //'no phone'

  //late - lazy initialization
  print('id: ${u1.id}'); //id is initializing when you access it

  //null-conditional cascade operator (?..)
  User? u2; //u2 is null
  u2 // ?.. - if u2 not null - modify fields
    ?..name = 'Mike'
    ..phone = '03';
  print('u2: ${u2?.phone?.length.toString()}'); //null

  //Nullable types in functions
  bool? isGood(String? item) {
    if (item == 'good') {
      return true;
    } else if (item == 'bad') {
      return false;
    }
    return null;
  }
  var good = isGood('bad') ?? false;

}

class User {
  User({required this.name}); //constructor
  String name; //not nullable property
  String? phone; //nullable property

  //late - lazy initialization
  //int x = calculate(); //error!!!
  //late - x will be initialized when you access it the first time.
  late int id = calculate();
  int calculate() {
    return name.length + 42;
  }
}

Комментариев нет:

Отправить комментарий