본문 바로가기

Dart

[Dart] Null Safety

널을 할당 가능하게 하려면 ? 기호를 추가하면 된다. 

 

void main() {
  int? a;
  a = null;
  print('a is $a.');
  String? name;
  name = null;
  print('you name is $name');
}
----------------------------[result]
a is null.
you name is null

 

리스트를 사용하는 경우 '?' 위치

 

void main() {
  List<String> aListOfStrings = ['one', 'two', 'three'];
  // 리스트 멤버가 없는경우는 , 빈 리스트 할당으로 ? 대체 가능
  List<String> aNullableListOfStrings = [];
  // 리스트 멤버가 없는경우는 , 타입<> 뒤에 ? 위치
  List<String>? aNullableListOfStrings1;
  // 리스트 요소중에 널이 있으면 <> 안에 ? 위치
  List<String?> aListOfNullableStrings = ['one', null, 'three'];

  print('aListOfStrings is $aListOfStrings.');
  print('aNullableListOfStrings is $aNullableListOfStrings.');
  print('aNullableListOfStrings1 is $aNullableListOfStrings1.');
  print('aListOfNullableStrings is $aListOfNullableStrings.');
}
------------------------------[result]
aListOfStrings is [one, two, three].
aNullableListOfStrings is [].
aNullableListOfStrings1 is null.
aListOfNullableStrings is [one, null, three].

 

The null assertion operator (!)

 

int? couldReturnNullButDoesnt() => -3;

void main() {
  int? couldBeNullButIsnt = 1;
  List<int?> listThatCouldHoldNulls = [2, null, 4];

  int a = couldBeNullButIsnt;
  // ! 위치 중요함, 문법의 구조에 따라서 ! 위치가 다름.
  // 널이 아니라고 확신할때, ! 추가하면 됨. 리스트의 첫번째 요소는 널이 아님
  int b = listThatCouldHoldNulls.first!; // first item in the list
  // 함수의 리턴값은 널이 절대 아니므로 함수명 바로 뒤에 ! 추가
  int c = couldReturnNullButDoesnt()!.abs(); // absolute value

  print('a is $a.');
  print('b is $b.');
  print('c is $c.');
}
----------------------------------[result]
a is 1.
b is 2.
c is 3.

 

변수가 널일 경우, 로직을 추가해서 회피하는 코드

 

int getLength(String? str) {
  // Add null check here
  if (str == null) {
    return 0;
  }
  else {
    return str.length;
  }  
}


void main() {
  print(getLength('This is a string!'));
}
-------------------------------[result]
17

 

Exception 처리

 

int getLength(String? str) {
  // Try throwing an exception here if `str` is null.
  if(str == null){
    throw Exception();
  }

  return str.length;
}

void main() {
  print(getLength(null));
}
-----------------------------------[result]
Uncaught Error: Exception

 

Late keyword

  • Don’t assign that variable a value yet.
  • You will assign it a value later.
  • You’ll make sure that the variable has a value before the variable is used.
class Meal {
  // 생성자가 없는 경우
  late String _description;

  void set description(String str) {
    _description = str;
  }

  String get description => _description;
}

void main() {
  final myMeal = Meal();
  myMeal.description = 'Feijoada!';
  print(myMeal.description);
}
------------------------------[result]
Feijoada!

 

Late circular references

The late keyword is helpful for tricky patterns like circular references. The following code has two objects that need to maintain non-nullable references to each other. Try using the late keyword to fix this code.

Note that you don’t need to remove final. You can create late final variables: you set their values once, and after that they’re read-only.

 

class Team {
  late final Coach coach;
}

class Coach {
  late final Team team;
}

void main() {
  final myTeam = Team();
  final myCoach = Coach();
  myTeam.coach = myCoach;
  myCoach.team = myTeam;

  print('All done!');
}
------------------------------[result]
All done!

 

Late and lazy

Here’s another pattern that late can help with: lazy initialization for expensive non-nullable fields. Try this:

  1. Run this code without changing it, and note the output.
  2. Think: What will change if you make _cache a late field?
  3. Make _cache a late field, and run the code. Was your prediction correct?
int _computeValue() {
  print('In _computeValue...');
  return 3;
}

class CachedValueProvider {
  // late 키워드가 없는 경우
  final _cache = _computeValue();
  int get value => _cache;
}

void main() {
  print('Calling constructor...');
  var provider = CachedValueProvider();
  print('Getting value...');
  print('The value is ${provider.value}!');
}
---------------------------[result]
Calling constructor...
In _computeValue...
Getting value...
The value is 3!

 

late 키워드가 있는 경우, 출력 순서가 변경된다.

 

int _computeValue() {
  print('In _computeValue...');
  return 3;
}

class CachedValueProvider {
  // late 키워드가 있는 경우
  late final _cache = _computeValue();
  int get value => _cache;
}

void main() {
  print('Calling constructor...');
  var provider = CachedValueProvider();
  print('Getting value...');
  print('The value is ${provider.value}!');
}
---------------------------[result]
Calling constructor...
Getting value...
In _computeValue...
The value is 3!

'Dart' 카테고리의 다른 글

[Dart] Class - getter, setter  (0) 2021.05.27
[Dart] Class - 선언 및 생성자  (0) 2021.05.27
[Dart] Stream 처리.  (0) 2021.05.01
[Dart] Future, async-await  (0) 2021.04.30
[Dart] 상속과 변수 초기화  (0) 2021.04.30