Flutter로 어플 만드는 것 생각 중이시죠? 키워드인 var, final, const로 변수 선언 하는 방법부터 배우셔야 합니다. 아래 글을 읽고 어플 만들기 첫걸음을 디뎌보죠.
Flutter 변수 선언 방법
Flutter 앱을 만들 때 가장 먼저 익혀야 하는 것 중 하나가 “변수 선언”입니다. Dart에서는 변수를 선언할 때 보통 아래 형태를 사용합니다.
키워드 + (타입) + 변수명 = 값;
여기서 키워드는 주로 var, final, const를 의미합니다. 세 키워드는 “값을 바꿀 수 있는지”와 “값이 언제 결정되는지”에서 차이가 나므로, 이 차이만 정확히 잡아두면 이후 문법이 훨씬 쉬워집니다.
var: 타입 추론 + 값 변경 가능
var는 초기값을 보고 타입을 자동으로 추론하도록 할 때 사용합니다. 또한 var로 선언한 변수는 같은 타입의 값으로 재할당(변경) 이 가능합니다.
핵심은 var를 쓸 때 타입을 같이 쓰지 않는다는 점입니다. var 자체가 타입 추론을 의미하므로, 뒤에 타입을 붙이면 문법 오류가 됩니다.
var a = 10;
위와 같이 작성하는 경우 변수명 a는 int로 추론되고, 값은 10으로 결정되는 것이죠. 이 값은 언제든지 바뀔 수 있습니다. 하지만 var는 한 번 타입이 추론되면 다른 타입으로 변경 불가합니다.
var a = 10; // a는 int로 추론됨
a = 20; // 같은 int이므로 재할당 가능
var a = 10;
a = "hello"; // 오류: a는 int로 추론되었기 때문에 String 대입 불가
final: 한 번만 대입
final은 딱 한 번만 값이 들어갈 수 있는 변수입니다. 즉, 초기화(대입) 이후에는 재할당이 불가능합니다.
const와의 가장 큰 차이는 final은 앱 실행 중(런타임)에 계산된 값으로도 초기화가 가능하다는 점입니다. 대표적으로 사용자 입력처럼 실행 중에 값이 정해지는 경우에 사용합니다.
final int b = int.parse(userInput);
위처럼 코드를 입력하면, 어플을 시작하고, 어플 사용자가 입력하는 숫자가 b의 값으로 결정되고, 이후에 변경이 불가합니다. 아래와 같이 코드를 입력하는 경우 오류가 뜨는 것이죠.
final int b = int.parse(userInput);
// b = 30; // 오류: final 변수는 재할당 불가
추가로 중요한 점이 있습니다. final은 “변수에 다른 값을 다시 대입(재할당)”하는 것을 막는 것이지, 객체 내부가 바뀌는 것까지 무조건 막는 것은 아닙니다. 예를 들어 리스트처럼 내부 수정이 가능한 타입이라면, 리스트 자체를 바꾸지는 못해도 내부는 아래와 같이 변경될 수 있습니다.
final list = <int>[1, 2];
list.add(3); // 가능: list 자체를 다른 값으로 재할당하는 게 아니라 내부를 수정
const: 컴파일 타임 상수(실행 전에 값이 확정)
const는 컴파일 시점(빌드 시점)에 값이 확정되는 상수입니다. 즉, 코드가 실행되기 전에 이미 값이 결정되어 있어야 합니다.
const int c = 30;
따라서 아래와 같이 사용자가 입력하는 코드는 작성이 불가합니다.
const int c = int.parse(userInput); // 오류: 컴파일 타임에 결정 불가
final vs const 차이 정리
-
final: 한 번만 대입 가능. 어플 실행 중 값 결정 -
const: 컴파일 타임 상수, 어플 실행 전 값 결정
결론
Dart에서 변수 선언은 var, final, const의 차이를 정확히 구분하는 것부터 시작합니다. 값이 바뀔 가능성이 있고 타입 추론을 활용하고 싶다면 var를 사용하되, var와 타입을 함께 쓰면 문법 오류가 나므로 둘 중 하나만 선택해야 합니다. 실행 중에 한 번 정해진 뒤 바뀌면 안 되는 값이라면 final이 적합하며, 사용자 입력이나 실행 중 계산 결과처럼 런타임에 결정되는 값도 담을 수 있습니다. 반대로 앱 실행 이전(빌드 시점)에 이미 확정되어 있어야 하는 진짜 상수는 const를 사용해야 하며, int.parse(userInput)처럼 런타임 값이 필요한 표현식은 const로 만들 수 없습니다. 실무에서는 “변경 가능성”과 “결정 시점(런타임/컴파일 타임)”을 기준으로 선택하면 실수가 크게 줄어듭니다.
FAQ
var는 무조건 타입을 생략해야 하나요?
var를 쓰는 경우에는 타입을 별도로 쓰지 않습니다. var 자체가 초기값을 기준으로 타입을 추론하라는 의미이기 때문에 var int a = 10;처럼 함께 쓰면 문법 오류가 됩니다. 타입을 명시하고 싶다면 int a = 10;처럼 타입 선언 방식으로 작성하면 됩니다.
var로 선언하면 값은 언제든지 바꿀 수 있나요?
var로 선언한 변수는 재할당이 가능하지만, 아무 타입으로나 바꿀 수 있는 것은 아닙니다. 한 번 초기화되면서 타입이 결정되면 같은 타입의 값으로만 변경할 수 있습니다. 예를 들어 var a = 10;이면 a = 20;은 가능하지만 a = "hello";는 불가능합니다.
final이면 “완전 불변”인가요?
final은 “변수에 다른 값을 다시 대입(재할당)할 수 없다”는 의미입니다. 하지만 리스트처럼 내부 수정이 가능한 객체를 final로 잡아두면, 변수 자체는 바꿀 수 없어도 객체 내부는 변경될 수 있습니다. 완전한 불변을 원하면 const 객체를 사용하거나, 불변 컬렉션/패턴을 함께 고려해야 합니다.
사용자 입력 값은 final로 받을 수 있나요?
가능합니다. final은 런타임에 계산되는 값을 담을 수 있으므로 final int b = int.parse(userInput);처럼 작성할 수 있습니다. 이 경우 사용자가 어떤 값을 입력하든 최초 한 번 결정된 뒤에는 b에 다른 값을 다시 대입할 수 없습니다.
사용자 입력 값을 const로 받으면 왜 안 되나요?
const는 컴파일 타임(빌드 시점)에 값이 확정되어야 합니다. userInput은 앱 실행 후에 들어오는 값이므로 빌드 시점에는 알 수 없고, int.parse(userInput) 역시 런타임 연산이기 때문에 const 초기화에 사용할 수 없습니다.
const는 숫자나 문자열에만 쓰는 건가요?
주로 리터럴(숫자, 문자열)과 컴파일 타임에 계산 가능한 상수 표현식에 쓰지만, const 생성자와 const 컬렉션처럼 객체에도 사용할 수 있습니다. 핵심 기준은 “빌드 시점에 값이 확정 가능한가”입니다.
final과 const 중 실무에서는 무엇을 더 많이 쓰나요?
상수처럼 보이지만 런타임 값이 섞이는 경우가 많기 때문에 final이 더 자주 등장하는 편입니다. 반면 진짜 상수(앱 전역에서 변하지 않는 설정 값, 고정된 키, 고정된 라벨 등)는 const가 적합합니다. 팀 컨벤션에 따라 상수는 const 우선, 불가하면 final로 두는 방식도 흔합니다.
var 대신 타입을 명시하는 int a = 10; 방식은 언제 쓰나요?
타입을 명확히 보여주고 싶거나, 코드 리뷰/유지보수 관점에서 타입을 즉시 드러내고 싶을 때 유용합니다. 특히 복잡한 제네릭 타입이나 함수 반환 타입이 한눈에 보이지 않을 때는 타입 명시가 가독성을 높입니다.
var x; 처럼 초기값 없이 var만 쓰면 어떻게 되나요?
초기값 없이 선언하면 타입 추론이 되지 않아 dynamic처럼 동작할 가능성이 커지고, 이후 어떤 타입이든 들어가게 되어 타입 안정성이 떨어질 수 있습니다. 초보 단계에서는 초기값을 함께 주어 타입이 명확히 결정되도록 작성하는 편이 안전합니다.
const로 선언하면 성능이 좋아지나요?
const는 동일한 상수 값을 재사용하는 방식으로 메모리/객체 생성 측면에서 이점이 있을 수 있습니다. 다만 성능을 위해 무조건 const를 남발하기보다는, 의미적으로 “빌드 시점 상수”가 맞는 곳에만 정확히 사용하는 것이 더 중요합니다.
“Flutter(Dart) 코드 작성 기본: var / final / const로 변수 선언”에 대한 1개의 생각