private 필드는 재할당하지 않으면 final로 선언해요

private 필드는 재할당하지 않으면 final로 선언해요

prefer_final_fields 린트 규칙은 나중에 재할당하지 않는 private 필드는 final로 선언하라고 권하는 규칙이에요. Stable 상태이고 공식 추천(Recommended) 규칙이며 자동 수정도 가능해요.

출처: Private field could be final.

본문

Effective Dart에서도 나오는 규칙이에요. 라이브러리 안에서 나중에 재할당되지 않는 private 필드는 final로 선언하세요.

필드를 가능하면 final로 선언하는 게 좋은 습관인 이유는, 실수로 값을 다시 바꾸는 일을 막아 주고 컴파일러가 최적화를 할 수 있게 해 주기 때문이에요.

BAD — 재할당하지 않는데 var로 선언했어요.

class BadImmutable {
  var _label = 'hello world!'; // LINT
  var label = 'hello world!'; // OK
}

BAD — 여러 필드 중 일부만 final이고 나머지엔 린트가 걸려요.

class MultipleMutable {
  var _label = 'hello world!', _offender = 'mumble mumble!'; // LINT
  var _someOther; // LINT

  MultipleMutable() : _someOther = 5;

  MultipleMutable(this._someOther);

  void changeLabel() {
    _label = 'hello world!';
  }
}

GOOD — 재할당하지 않는 필드는 전부 final로 선언했어요.

class GoodImmutable {
  final label = 'hello world!', bla = 5; // OK
  final _label = 'hello world!', _bla = 5; // OK
}

GOOD — 실제로 값을 바꾸는 필드라면 var로 남겨도 괜찮아요.

class GoodMutable {
  var _label = 'hello world!';

  void changeLabel() {
    _label = 'hello world!';
  }
}

BAD — 모든 생성자에서 값을 할당하는 필드도 사실상 재할당이 아니에요.

class AssignedInAllConstructors {
  var _label; // LINT

  AssignedInAllConstructors(this._label);

  AssignedInAllConstructors.withDefault() : _label = 'Hello';
}

GOOD — 초기화 없이 선언만 하고 생성자에서만 값을 정하는 필드는 var라도 괜찮아요.

class NotAssignedInAllConstructors {
  var _label; // OK

  NotAssignedInAllConstructors();

  NotAssignedInAllConstructors.withDefault() : _label = 'Hello';
}

규칙 켜기

analysis_options.yaml 파일의 linter > rules 아래에 prefer_final_fields를 추가하면 돼요.

linter:
  rules:
    - prefer_final_fields

YAML 맵 문법으로 설정한다면 이렇게 써요.

linter:
  rules:
    prefer_final_fields: true

더 알아보기

  • 선언 시점에 값을 알 수 없는 필드(생성자에서만 값이 정해지는 필드)는 final로 쓸 수 없으니 var로 남겨요.