값이 채워지기 전에 쓰인 non-nullable 지역 변수

값이 채워지기 전에 쓰인 non-nullable 지역 변수 (not_assigned_potentially_non_nullable_local_variable)

Dart의 non-nullable 안전성과 관련된 진단이에요. 지역 변수가 non-nullable 타입인데, 어느 시점에 어떤 값도 대입되지 않은 채로 쓰이고 있다는 뜻이에요. 메시지는 "The non-nullable local variable '{0}' must be assigned before it can be used." — "non-nullable 지역 변수 '{0}'은(는) 사용되기 전에 값이 반드시 대입되어야 해요"라고 알려줘요.

출처: not_assigned_potentially_non_nullable_local_variable

본문

언제 발생하나요?

애널라이저가 지역 변수의 참조를 검사하다가 이 변수가 아래 성질을 전부 갖고 있으면 이 진단을 내요.

  • 타입이 non-nullable이에요.
  • 초기화식(initializer)이 없어요.
  • late로 표시되지 않았어요.
  • 그리고 애널라이저가 정확한 대입 분석(definite assignment analysis)에 기반해서, 해당 참조 지점 전에 값이 대입된다는 걸 증명하지 못해요.

non-nullable 변수는 null이 될 수 없으니, 어떤 경로로든 사용 전에 반드시 값이 채워져 있어야 해요. 그걸 보장하지 못할 때 이 진단이 나오는 거예요.

예시

다음 코드는 xnull 값을 가질 수 없는데, 값이 대입되기 전에 참조되고 있어서 이 진단이 발생해요.

String f() {
  int x;
  return x.toString();
}

다음 코드는 x에 대한 대입이 실행되지 않을 수도 있어서, xnull일 수 있기 때문에 진단이 발생해요.

int g(bool b) {
  int x;
  if (b) {
    x = 1;
  }
  return x * 2;
}

다음 코드는 애널라이저가 대입 분석(definite assignment analysis)으로 x가 값 없이 참조되지 않는다는 걸 증명할 수 없어서 진단이 발생해요.

int h(bool b) {
  int x;
  if (b) {
    x = 1;
  }
  if (b) {
    return x * 2;
  }
  return 0;
}

두 번째 if (b) 블록 안에서 x * 2가 참조되는 시점에 x에 값이 들어 있다는 걸 스스로 따져보면 애매한 부분이 남는 걸 알 수 있어요. 첫 번째 if (b)가 실행되지 않았다면 x는 여전히 빈 상태니까요.

어떻게 고치나요?

null이 타당한 값이라면, 변수를 nullable 타입으로 바꿔요.

String f() {
  int? x;
  return x!.toString();
}

null이 타당하지 않고, 합리적인 기본값이 있다면 초기화식을 추가해요.

int g(bool b) {
  int x = 2;
  if (b) {
    x = 1;
  }
  return x * 2;
}

그게 아니라면, 값이 접근되기 전에 모든 코드 경로에서 값이 대입되도록 보장해요.

int g(bool b) {
  int x;
  if (b) {
    x = 1;
  } else {
    x = 2;
  }
  return x * 2;
}

변수를 late로 표시할 수도 있어요. 그러면 이 진단은 사라져요. 다만 값이 대입되기 전에 접근하면 런타임에서 예외가 던져지거든요. 애널라이저가 대입 분석으로 증명할 수는 없지만, 당신 자신이 "항상 값이 대입될 거야"라고 확신할 수 있을 때만 이 방법을 쓰는 게 좋아요.

int h(bool b) {
  late int x;
  if (b) {
    x = 1;
  }
  if (b) {
    return x * 2;
  }
  return 0;
}

더 알아보기

  • non-nullable 안전성 전반은 Null safety 문서에서 확인할 수 있어요.
  • 다른 진단과 함께 보려면 Diagnostics 목록을 참고하세요.