Flutter/Dart

[DART] Sound Null Safety in dart

연화 2025. 1. 6. 18:05

 

ㅇㅇ널 세이프티(Null Safety)는 개발자가 널 에러를 피할 수 있도록 도와주는 다트 프로그래밍 언어의 기능입니다.
이 기능은 사운드 널 세이프티 인 다트(Sound Null Safety in dart)라고 불리며, 이를 통해 개발자는 코드 작성 시점에 널 에러를 잡을 수 있습니다.

 

Sound Null Safety in dart 이란 (Sound Type System)

런타임 중에 null 포인터 예외를 방지하기 위해 Dart 컴파일러가 코드를 분석하고 컴파일할 때 타입 시스템에서 엄격한 규칙을 적용하는 것을 의미합니다.

정리하면, Dart 컴파일러가 코드를 분석하고, null이 될 수 있는 타입과 null이 될 수 없는 타입을 분명히 구분해 주기 때문에, 우리가 실수로 null을 넣거나 반환하게 되면 빌드(컴파일) 시점에 오류를 발견할 수 있습니다.
이를 사운드 널 세이프티(Sound Null Safety)라고 하며, 런타임에서의 null 참조 에러 를 효과적으로 예방해줍니다.

// Null Safety란?
// 개발자가 널 에러를 피할 수 있도록 도와주는 다트 언어의 기능
void main() {
  String name = '길동';
  int age = 30;

  // String? = 스트링옵셔널 타입
  // null을 허용
  String? nullableName;
  int? nullableAge;

  print('name : ${name}');
  // print('nullableName : ${nullableName.length}'); 컴파일 시점에 오류를 미리 확인할 수 있다.
  print('nullableAge : ${nullableAge}');

  // 방어적 코드도 작성해보자.
  if (nullableName != null) {
    print(nullableName.length);
  }
}

 

1) Null Check 연산자와 Null 병합 연산자

null 체크 연산자 ( ?. )
null값일 수도 있는 객체의 속성이나 메서드에 안전하게 참조할 수 있도록 오류를 방지합니다.

null 병합 연산자 ( ?? )
변수나 표현식의 값이 null 인 경우 대체값을 지정할 수 있습니다.

// null check 연산자 ( ?. ) 와 null 병합 연산자 ( ?? )
void main() {
  // 1. 널 체크 연산자
  String? userName = getNullableUserName();
  // 널 체크 연산자
  int? userNameLength = userName?.length;

  print('사용자 이름의 길이 값 : ${userNameLength}');
  print('==========================================');

  // 2. 널 병합 연산자
  String finalUserName = userName ?? '홍길동';
  print('finalUserName : ${finalUserName}');

  // 3. 널 체크 연산자  ( ?. ) 와 널 병합 연산자 ( ?? ) 를 함께 사용하는 예시
  String upperOrNoName =
      userName?.toUpperCase() ?? 'NO_NAME'; // toUpperCase : 대문자로 변환ㅡ
}

// 함수를 만들어 보자.
// 선택적 명명 매개변수
String? getNullableUserName({String? name}) {
  return name;
}

 

2) Null 억제 연산자 (null assert 연산자)

null 억제 연산자 ( ! )
개발자가 해당 값이 null 아님을 확신하고, 예외를 발생시키지 않을 때 유용하게 사용할 수 있습니다.

// null 억제 연산자 (!)
void main() {
  // 이 코드는 절대 널이 될 수 없다.
  String? nullableName = getNullableName();

  // 1. null 억제 연산자 사용해 보기
  // null 체크 연산자 또는 null 병합 연산자를 사용할 수 있지만
  // null이 아님을 확신한다면 개발자가 null 억제 연산자를 사용할 수 있다.
  String forcedName = nullableName!;
  print('forcedName = ${nullableName}');
}

String? getNullableName() {
  return '홍길동';
}

 

Late 키워드에 대해 알아 보자

지연 초기화를 의미하며 변수를 선언만 해두고 나중에 필요할 때 초기화할 수 있도록 도와주는 문법입니다.
보통은 final 키워드와 함께 많이 사용합니다.

// late 키워드
void main() {
  // 1. late 키워드를 사용해 보자
  late String greeting;

  greeting = getGreetingMessage();
  print(greeting);

  print('--------------------------------');

  // 2. late final 변수
  late final int number;
  number = 100;
  print('number ${number}');

  //컴파일 시점에 사용시 오류 확인
  late String notAssigned;
  // print(notAssigned);
}

String getGreetingMessage() {
  print('함수 호출'); // 로깅을 찍어 본다. 디버깅
  return 'Hello, Dart!';
}

 

💡 late 키워드를 사용하는 이유
변수를 정의할 때 초기화할 수 있는 시점이나 방법이 없는 경우
변수를 생성자나 함수에서 나중에 초기화해야 하는 경우
변수를 사용하기 전에 null 여부를 확인하거나 예외 처리를 할 필요가 없는 경우

 

 

 

아래의 문헌을 참고하여 작성된 포스팅입니다.
최주호, 김근호, 이지원(공저) 만들면서 배우는 플러터 앱 프로그래밍』, 앤써북, 2023.

'Flutter > Dart' 카테고리의 다른 글

[DART] OOP 연관관계와 Mixin  (1) 2025.01.07
[DART] 상속(Inheritance)이란 무엇인가요?  (0) 2025.01.06
[DART] 클래스와 인스턴스  (2) 2025.01.03
[DART] 익명함수와 화살표함수  (1) 2025.01.03
[DART] 기본 연산자  (0) 2025.01.03