[flutter] Sound Null Safety

2023. 1. 15. 23:39flutter

1. Null 이란?

 

"값이 없음" 을 의미합니다.

 

0도 아니고 ""도 아닙니다. 정말 값 자체가 없는 상황을 이야기하는 것입니다.

 

 

2. Sound Null Safety

 

Dart 2.12와 Flutter 2 이후부터는 Sound Null Safety를 지원합니다.

 

Sound Null Safety는 프로그램에 "모든 변수에는 값이 할당되어야 한다"는 규칙을 적용합니다. 그리고, 값이 할당되지 않으면 컴파일러가 에러 메세지를 돌려줍니다.

 

Null 관련 에러는 앱이 실행될 때(runtime)에 많이 생깁니다.

 

그렇게 찾은 에러는 디버깅이 굉장히 어려워서, 코딩을 하는 도중에 컴파일러가 에러를 잡아주면 어떨까 하는 생각이 Sound Null Safety를 만들었습니다.

 

간단한 예시를 생각해볼게요.

void main() {
  int value;     
  value = null;  //<------ 여기서 문제 발생!
  print('value is $value.');
}

 

주석을 보면, int형 변수 value에 null을 대입해주고 있습니다.

 

null은 값이 아니기 때문에 대입이라는 표현이 어울리지 않지만, 값이 없다는 정보를 준다고 생각하면 됩니다.

 

Sound null safety가 적용되는 상황에는 이런 에러 메세지를 줍니다.

 

Int 형 변수에 Null이 할당될 수 없다는 에러 메세지를 줍니다.

 

컴파일러는 해결책으로 두 가지 방법을 제시하고 있습니다. 

1. null을 정수값으로 바꾸기 (우변 바꿔!)

2. 변수의 자료형을 바꾸기 (좌변 바꿔!)

 

 

1번 해결책으로 문제를 해결하면 이렇게 됩니다.

// 1번 해결책

void main() {
  int value;     
  value = 3;  //<------ 정수를 대입해주기!
  print('value is $value.');
}

 

 

2번 해결책으로 문제를 해결하면 이렇게 됩니다.

// 2번 해결책

void main() {
  int? value;    // <-- 변수의 자료형을 바꿔준다! 
  value = null;  
  print('value is $value.');
}

 

여기서 등장한 ?는 Sound Null Safety 가 적용될때도 변수에 null이 대입될 수 있도록 해주는 기호입니다. 

 

 

3.  ? 의 의미

 

"변수에 null 대입을 허용하고 싶을 때 사용하는 기호"

 

Sound Null Safety는 변수에 Null의 할당을 차단하여 에러를 없앴습니다.

 

그러나, null의 대입은 프로그래밍을 하면서 유용하고 불가피한 상황이 많아서 이를 부분적으로 허용해주는 문법이 존재합니다.

 

그것이 바로 ?의 존재이유입니다.

 

 

간단한 예시를 생각해볼게요.

void main() {
  int a;  // int  는 null이 대입 불가능한 정수형 변수
  int? b; // int? 는 null이 대입 가능한 정수형 변수  
  
  a = 3;
  b = 4;
  
  print('a is $a.');
  print('b is $b.');
}

 

이때는 a와 b값에 각각 3, 4를 대입하면 아무문제 없이 "a is 3." "b is 4"가 출력됩니다.

 

 

문제는 아래에서 발생합니다.

void main() {
  int a;  // int  는 null이 대입 불가능한 정수형 변수
  int? b; // int? 는 null이 대입 가능한 정수형 변수   
  
  a = null;
  b = null;
  
  print('a is $a.');
  print('b is $b.');
}

b에는 null이 대입되어도 문제가 없지만, a는 일반적인 int 형 변수이기 때문에 null 대입이 불가능합니다.

 

4.  ! 의 의미 (null assertion operator)

"Null 대입이 가능한 변수이지만, 절대 null이 대입 되지 않는다는 것을 표시하기 위한 기호"

 

void main() {
  
  int? a() => 3;
  
  int result = a().abs();
  
  print('result is $result.');
}

 

a는 null이 대입가능한 정수를 반환하는 함수이고, 반환값은 항상 3입니다.

 

물론, a는 다른 정수값이나 null값을 반환할 수 있습니다.

 

그 이후, int형 변수 result에 a().abs()를 대입하였습니다. abs()는 정수의 절댓값을 반환하는 매서드입니다.

 

Sound null safety가 적용되는 상황에는 이런 에러 메세지를 줍니다.

 

 

abs() 매서드는 null이 될 수도 있는 변수에 대해서는 작동하지 않는다는 에러 메세지입니다.

 

컴파일러는 해결책으로 두 가지 방법을 제시하고 있습니다.

1. ? 이용해서 null의 대입이 가능하게 하기

2. a()값이 절대 null이 될 수 없다고 알려주기

 

 

1번 해결책으로는 문제를 해결할 수 없습니다.

 

코드에 등장한 어떠한 변수에 대해 null의 대입을 가능하게 한다고 해서 abs() 매서드를 정상작동시킬 수는 없습니다.

 

 

2번 해결책으로 문제를 해결할 수 있습니다.

void main() {
  
  int? a() => 3;
  
  int result = a()!.abs(); // !를 추가해줬다
  
  print('result is $result.');
}

 

a()값은 int? 형 값을 반환하기 때문에 null 값을 반환하는 것도 가능합니다.

 

그러나, abs() 매서드가 정상작동하기 위해서는 a()의 반환값으로 null값이 가능은 하지만, 절대 null값을 될 수는 없다는 것을 알려주기 위해 !를 사용합니다.

 

5.  ?? 의 의미 (null - coalescing operator)

"변수값이 null이면 프로그래머가 지정한 다른 값으로 처리하라는 기호"

 

null을 이용하는 것이 불가피하지만, 변수가 null이 할당된 채로 프로그램에는 사용되는 것을 바라지 않을 때,

 

특정 값을 대입해줄 수 있는 문법입니다.

 

void main() {
    String? exString;
    print(exString ?? "alternate");
  
    exString = "Hello world";
    print(exString ?? "alternate");
}

 

위의 코드의 결과는 아래와 같습니다.

alternate
Hello world

 

 

6.  late 의 의미

"non-nullable변수이지만 값의 할당은 나중에 한다는 것을 알려주는 키워드"

 

플러터에서는 모든 변수가 기본적으로 non - nullable 변수입니다.

 

즉, null값의 대입이 불가능한 변수라는 말입니다.

 

그러나, 코딩을 하다보면, non - nullable 변수에 값이 없으면 돌아가지 않는 상황이 발생합니다.

 

이런 경우, dummy value를 대입해주지 않고, late키워드를 사용합니다.

 

late 키워드를 사용하면 플러터는 아래와 같이 이해합니다.

1. 값 대입해야 하는거 알고있는데, 지금은 값을 대입하지 않을래

2. 나중에 대입할게

3. 그 변수 사용하기 전에는 무조건 대입할 것 약속해!

 

late 키워드는 아래와 같이 사용합니다.

late int exInt;

 

즉, 자료형 앞에 late를 붙여주기만 하면 됩니다.

 

 

 

 

[참고 자료]

https://dart.dev/null-safety

 

Sound null safety

Information about Dart's null safety feature

dart.dev

https://medium.com/flutter-korea/flutter의-null-safety-이해하기-dd4ee1f7d6a5

 

flutter의 null safety 이해하기

flutter를 이루고 있는 dart의 null safety에 대해 알아보겠습니다.

medium.com