[Dart] Null 안전성
Dart에서 Null 안전성과 그를 보장하기 위한 장치들을 알아보자!
- Null 안전성 (Null Safety)
- Null Point Exception을 프로그램 실행 전 코드를 작성하는 시점에서 점검하는 것을 뜻한다.
Null Point Exception
객체가 특정 값이 아닌null
을 가리킬 때 발생하는 오류이다.
컴파일러가 미처 걸러내지 못하고 프로그램 실행 중에 발생할 경우 치명적일 수 있다.
Dart는 Null 안전성을 지원하여 NPE 발생 가능성을 낮추었다.
이러한 Null 안전성을 지원하는 언어에서의 변수 선언은 두 가지로 구분할 수 있다.
- Nullable
- 컴파일러에 이 변수에
null
을 대입할 수 있음을 명시한다.
NPE를 고려하지 않고 Nullable 변수를 사용 시 컴파일러가 오류를 알려준다.
- NonNull
- 변수에
null
을 대입할 수 없다.null
이 대입되면 코드 작성 시 컴파일러가 오류를 알려준다.
1. Nullable 변수 선언
Nullable 변수를 선언하기 위해서는 타입 뒤에 ?
를 붙이면 된다.
1
2
int? cnt1 = null;
assert(cnt1 == null);
Dart에서 모든 변수는 객체이다.
가령 Number
또한 객체이기에, Number
타입 변수도 초기값으로 null
을 가질 수 있다.
그런데 변수를 선언함과 동시에 초기값을 지정하지 않을 경우 변수는 null
로 초기화된다.
JavaScript에서 변수를 초기화하지 않을 경우
undefined
로 초기화되는 것과 유사하다.
따라서 Non-Null 변수를 선언과 동시에 초기화하지 않으면 오류가 발생한다.
다만, 이는 전역 변수와 클래스의 멤버 변수에 한해서 적용된다.
즉, 함수에서 지역 변수를 Non-Null로 선언할 때에는 초기화할 필요가 없다.
1
2
3
4
5
6
7
8
9
10
int cnt; // 전역에서 Non-Null을 초기화하지 않아서 ERROR
class testClass() {
int cnt; // 클래스 내에서 Non-Null을 초기화하지 않아서 ERROR
}
void testFun() {
int cnt; // 정상적인 코드
cnt = null; // Non-Null에 null을 대입해서 ERROR
}
물론 이 경우에도 초기값을 대입하기 전에 변수를 사용하려하면 오류가 발생할 것이다.
2. var 와 dynamic 타입의 Null 안전성
2.1 var
우리는 방금 전 var
로 선언한 변수의 타입을 컴파일러가 추론한다는 것을 배웠다.
이때 var
변수의 null
허용 여부 또한 대입 값에 따라 타입과 함께 결정된다.
따라서 var
뒤에는 ?
를 붙일 수 없다.
2.2 dynamic
dynamic
타입은 모든 타입의 데이터를 사용할 수 있기에, 독자들은 이렇게 생각할 것이다.
?
붙여봤자 의미가 없는데 그럼var
처럼?
를 못붙이지 않을까?
모든 타입의 데이터에는 Nullable 또한 포함될 것이므로 이러한 추론은 합리적인 것으로 보인다.
그런데 이게 뭐람?
1
2
3
4
5
6
7
8
9
dynamic x = 10;
dynamic y;
dynamic? z;
void testFun() {
x = null;
y = null;
z = null;
}
dynamic
의 경우 ?
를 뒤에 붙여도 상관이 없다!
물론 그걸 붙인다고 의미는 없다
3. Non-Null 변수의 초기화 미루기
그런데 변수를 선언함과 동시에 초기값을 지정하지 않을 경우 변수는
null
로 초기화된다.
따라서 Non-Null 변수를 선언과 동시에 초기화하지 않으면 오류가 발생한다.
앞서 우리는 Non-Null 변수의 경우 선언과 함께 초기화를 해야 함을 배웠다.
그런데 변수를 null
인 상태로 이용하다 필요할 때에 값을 결정해야 하는 경우는 어떻게 할까?
이럴 때 late
연산자를 쓰면 된다.
당신을 걱정하는 컴퓨터에게 “알빠노?” 를 박아보자.
1
2
3
4
5
6
7
8
int x; // 전역에서 Non-Null을 초기화하지 않아서 ERROR
late int y; // 정상적인 코드
void main() {
print("${y + 1}"); // 변수를 사용하기 전에 초기화하지 않아서 ERROR
y = 1;
print("${y + 1}"); // 정상적인 코드
}