Dart: final 과 const

stop mutating!

Kyungkoo Kang
Dartlang korea
4 min readJul 30, 2019

--

dart korea img

최근 모바일 프로그래밍에서는 변수에 한번 설정한 값을 변경하지 못하도록 하는 경우를 손쉽게 찾아볼 수 있다. 이러한 기능은 특히 멀티 스레드 환경에서 해당 값이 변경되지 않음을 보장하기 때문에 더욱 예측 가능하고 간결한 코드를 작성할 수 있게 해준다. 다트에서는 finalconst 키워드를 통해 변수에 설정한 값을 변경 할 수 없게 하는 기능을 제공한다.

final 과 const 선언

finalconst 는 아래와 같은 방식으로 선언한다.

final double pi = 3.141592;
const double e = 2.71828;

위에서 정의된 pie 는 이제 다른 값으로 변경할 수 없다. 다른 값을 변경하려고 시도하면 컴파일 오류가 발생한다.

finalconst 는 한번 설정한 값을 변경할 수 없게 한다는 공통점이 있는 반면, 차이점도 존재한다.

const 의 경우, 컴파일 타임에서 상수를 정의할 수 있다. 즉, const 로 정의한 상수는 런타임에서 정의되는 값을 설정할 수 없다는 의미다. 예를 들어 DateTime.now() 의 경우 런타임에서 호출 될 때마다 결과 값이 다른데 이러한 값은 const 로 설정할 수 없다. 결국 const 로 설정하는 값은 대부분 리터럴이 될 것이다.

반면, final 은 런타임에서 결정되는 값도 설정할 있다.

final DateTime now = DateTime.now(); // 문제 없음
// const DateTime now = DateTime.now(); // compile error

위 코드에서 const DateTime now = DateTime.now(); 코드를 활성화 한 상태에서 실행할 경우 아래와 같은 오류를 확인할 수 있을 것이다.

Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const now = DateTime.now();

그렇다고 모든 인스턴스화 과정에서 const를 사용할 수 없는 것은 아니다. 이를 위해 Color 클래스를 살펴보도록 하자.

const Color(int value)

Color 클래스의 생성자는 const로 선언되어 있으며, 이러한 생성자를 사용하여 선언하는 변수에는 const를 사용할 수 있다.

const color = Color(0xFF42A5F5);

반면, 앞에서 살펴본 DateTime.now() 의 경우, 생성자를 살펴보면 const로 선언되어 있지 않기 때문에 이를 인스턴스화 할 때에는 const를 사용할 수 없다.

finalconst는 배열을 선언하는 과정에서 또 다른 차이점을 발견할 수 있다. 먼저 아래 코드를 살펴보자.

final List<String> languages = [];
const List<String> companies = [];
languages.add('dart');/*
// compile error
companies.add('Google');
languages = ['Java'];
*/

languagesfinal 로 선언되어 있음에도 불구하고 배열에 값을 추가 할 수 있지만, const 로 선언된 companies 배열에는 값을 추가할 수 없다. 대신 두 배열 모두 새로운 배열로 변경하는 것은 불가능 하다. 결국 final 로 선언된 변수는 해당 변수에 새로운 값이 설정되는 것은 불가능하지만, 객체나 배열에 값을 추가하는 행위에 대해서는 관여하지 않는다는 것을 확인 할 수 있다.

Conclution

서두에 언급한 바와 같이 변수에 선언한 값을 변경하지 못하게 하면 예기치 않은 상황에서 값이 변경되어 발생하는 문제들을 손쉽게 해결할 수 있다. 특히 멀티 스레딩을 지원하는 경우에는 접근하는 변수의 값이 불변함을 보장할 수 있기 때문에 별도의 예외 처리 없이 간결하면서도 동작을 확신하는 코드를 작성할 수 있다. 다트 역시 이러한 기능을 제공함으로서 개발자가 더욱 예측 가능하며 견고한 코드를 작성할 수 있게 해준다. 다트의 const 는 변수명 앞이 아닌 인스턴스 선언 부 앞에 정의하는 경우가 있는데, 다트 2.x 부터는 위에서 설명한 방식을 권고하기 때문에 크게 신경 쓸 필요가 없으니 참고하도록 하자.

References

--

--