Dart에는 "초기화되지 않은 메모리"라는 개념이 없고 명시적으로 null로 초기화하지 않아도 괜찮음
Item? bestDeal(List<Item> cart) {
// good case
Item? bestItem;
// bad case
// Item? bestItem = null;
for (final item in cart) {
if (bestItem == null || item.price < bestItem.price) {
bestItem = item;
}
}
return bestItem;
}
// good case
void error([String? message]) {
stderr.write(message ?? '\n');
}
// bad case
void error([String? message = null]) {
stderr.write(message ?? '\n');
}
// good case
if (nonNullableBool) { ... }
if (!nonNullableBool) { ... }
// bad case
if (nonNullableBool == true) { ... }
if (nonNullableBool == false) { ... }
// good case
// 값이 null 일 때, 표현식이 false로 처리됨
if (nullableBool ?? false) { ... }
// 값이 null 일 때, 표현식이 false로 처리되고 아닐 때는 변수 값으로 처리
if (nullableBool != null && nullableBool) { ... }
// bad case
// 값이 null이라면 정적 에러 발생
if (nullableBool) { ... }
// 값이 null 일 때, false로 처리
if (nullableBool == true) { ... }
nullableBool == true는 실행 가능한 표현식이지만, 아래 이유로 사용하지 않는다
- 코드가 null과 관련이 있음을 나타내지 않음
- 명백히 null과 관련이 없기 때문에, 항등 연산자가 중복되어 제거될 수 있는 non-nullable의 경우로 쉽게 오인될 수 있다. 왼쪽의 boolean 표현식이 null일 가능성이 없을 경우에만 true이고, null을 생성할 수 있을 떄는 그렇지 않다
- 해당 형식의 boolean 로직은 알아보기 힘들다. nullableBool이 null이라면, nullableBool == true는 조건식이 false로 평가된다는 것을 의미
-> ?? 연산자롤 null이 발생할 수도 있는 상황에서 더 명확한 표현이 가능하고, 중복된 연산자로 헤깔릴 가능성이 줄어듬
-> ?? 같은 null-aware 연산자를 조건식에 사용하는 것은 변수를 non-nullable 타입으로 반환하지 않음
-> if문의 바디에서 변수의 타입을 변환하고 싶다면, ?? 보다 명시적으로 != null 확인하는 것이 좋다
class UploadException {
final Response? response;
UploadException([this.response]);
String toString() {
final response = this.response;
if (response != null) {
return 'Could not complete upload to ${response.url} '
'(error code ${response.errorCode}): ${response.reason}.';
}
return 'Could not upload (no response).';
}
}