Flutter
Flutter Day 3-1: Dart Null Safety
@leem
2025. 1. 6. 15:04
1. 널 세이프티(Null Safety)란?
널 세이프티(Null Safety)는 다트(Dart) 언어에서 널(null)로 인한 오류를 방지하기 위한 기능입니다.
다트 컴파일러는 널이 될 수 있는 타입과 널이 될 수 없는 타입을 명확히 구분하여,
컴파일 시점에 잘못된 널 참조를 미리 감지해 줍니다.
Sound Null Safety란?
- 사운드 타입 시스템(Sound Type System):
컴파일러가 널 안전성 규칙을 엄격히 적용하여, 런타임 중 널 포인터 예외를 방지합니다. - 잘못된 널 참조는 프로그램을 중단시키는 주요 원인 중 하나입니다.
널 세이프티는 이를 방지하여 안정적인 코드를 작성하도록 돕습니다.
2. 기본 사용법
void main() {
String name = '길동'; // 널 허용하지 않는 String 타입
int age = 30;
String? nullableName; // 널 허용 String 타입
int? nullableAge; // 널 허용 int 타입
print('name: ${name}');
// print(nullableName.length); // 컴파일 오류: nullableName이 null일 수 있음
print('nullableAge: ${nullableAge}');
// 방어적 코드
if (nullableName != null) {
print(nullableName.length); // null이 아닌 경우에만 안전하게 사용
}
}
- String: null 값을 허용하지 않는 타입.
- String?: null 값을 허용하는 옵셔널 타입.
- 컴파일 시점 오류 감지: nullableName.length는 null 가능성이 있으므로 오류 발생.
3. 널 체크 연산자 (?.)와 널 병합 연산자 (??)
널 체크 연산자 (?.)
객체가 null인지 확인한 후, null이 아니면 속성이나 메서드에 접근합니다.
널 병합 연산자 (??)
값이 null이면 기본값을 반환합니다.
void main() {
// 널 체크 연산자
String? userName = getNullableUserName();
int? userNameLength = userName?.length; // null이면 null 반환
print('사용자 이름의 길이: $userNameLength');
// 널 병합 연산자
String finalUserName = userName ?? '홍길동'; // null이면 기본값 사용
print('finalUserName: $finalUserName');
// ?.와 ?? 함께 사용
String upperOrNoName = userName?.toUpperCase() ?? 'NO_NAME'; // null 체크 후 기본값
print('upperOrNoName: $upperOrNoName');
}
String? getNullableUserName({String? name}) {
return name;
}
출력 결과
사용자 이름의 길이: null
finalUserName: 홍길동
upperOrNoName: NO_NAME
4. 널 억제 연산자 (!)
널 체크 없이 null이 아님을 확신하고, 강제로 값을 사용합니다.
void main() {
String? nullableName = getNullableName();
// null 억제 연산자 사용
String forcedName = nullableName!;
print('forcedName: $forcedName');
}
String? getNullableName() {
return '홍길동';
}
주의
- nullableName이 실제로 null이면 런타임 오류가 발생합니다.
반드시 null이 아님을 확신할 때만 사용하세요.
5. late 키워드
변수를 나중에 초기화할 때 사용합니다.
초기화하지 않고 사용하려 하면 컴파일러가 오류를 감지합니다.
void main() {
// late 변수 선언
late String greeting;
greeting = getGreetingMessage();
print(greeting);
// late final 변수
late final int number;
number = 100; // 초기화
print(number);
// 초기화하지 않은 late 변수 사용 시 오류
late String notAssigned;
// print(notAssigned); // 오류 발생
}
String getGreetingMessage() {
print('함수 호출됨');
return 'Hello, Dart!';
}
출력 결과
함수 호출됨
Hello, Dart!
100
- late: 변수를 지연 초기화. 필요할 때 값을 설정.
- late final: 초기화 후 변경 불가능.
- 초기화하지 않고 사용하면 컴파일 오류 발생.
6. Dart Null Safety의 핵심 요약
기능 | 설명 | 예제 |
? (null 가능 타입) | null 값을 허용하는 타입. | String? nullableName; |
?. | null이면 null 반환. null이 아니면 속성/메서드 접근. | nullableName?.length |
?? | null이면 기본값 반환. | nullableName ?? '기본값' |
! (null 억제) | null 아님을 확신할 때 사용. null이면 런타임 오류 발생. | nullableName! |
late | 나중에 초기화되는 변수. 초기화하지 않고 사용 시 컴파일 오류. | late String greeting; greeting = 'Hi'; |