var 잘못하면 dynamic, Object? 처리

Dart(Flutter)에서 var는 “타입을 자동으로 정해주는 키워드”로 알려져 있습니다. 그래서 많은 초보자가 var를 “타입을 안 써도 되는 편한 문법” 정도로만 이해하고 넘어가는데, 이 과정에서 자주 생기는 오해가 하나 있습니다. var는 보통 안전하게 타입을 추론해 고정해주지만, 작성 방식이 조금만 어긋나면 결과적으로 dynamic처럼 느슨해지거나, 혹은 Object?로 다뤄야 하는 상황이 생긴다는 점입니다. 이 글에서는 “var를 잘못 쓰면 왜 dynamic/Object?처럼 취급되는 느낌이 나는지”를 정확히 정리해드리겠습니다.

var 초기값이 있으면 타입이 고정

var는 초기값을 보고 타입을 추론합니다. 그리고 그 타입은 이후에 고정됩니다. 즉, var는 타입이 없는 게 아니라 “컴파일러가 타입을 정해준 변수”입니다.

var x = 1;   // int로 추론되어 고정
x = 2;       // OK
x = "a";     // 컴파일 에러 (int에 String 대입 불가)

이 경우 var는 오히려 실수를 줄여줍니다. 다른 타입을 넣는 순간 컴파일 단계에서 바로 막아주기 때문입니다.

var이 dynamic 처리되는 경우

문제가 되는 패턴은 아래처럼 초기값 없이 var를 선언하는 경우입니다.

var x;       // 초기값 없음 → 추론 불가 → dynamic처럼 동작
x = 1;       // OK
x = "a";     // OK

초기값이 없으면 추론할 근거가 없고, 이때 지역 변수는 사실상 dynamic 구간으로 들어갑니다.
즉, “var를 잘못 쓰면 dynamic이 된다”는 말은 보통 var x; 패턴을 경고하는 표현입니다.

이 상태에서는 컴파일러가 타입 관련 실수를 강하게 잡아주기 어렵고, 실수는 런타임에서 문제로 드러날 가능성이 커집니다.

dynamic 위험한 이유

dynamic은 타입 검사와 멤버 검사를 느슨하게 만들어, 컴파일 단계에서 잡힐 오류가 실행 중으로 넘어가기 쉽습니다.

dynamic d = "hi";
d.notARealMethod();  // 컴파일은 통과, 실행 중 NoSuchMethodError 가능

초보자가 var x;를 자주 쓰면, 코드 전체가 이런 위험한 성격을 띠기 쉬워집니다. 타입이 안정적으로 굳지 않기 때문이죠.

Object? 언급되는 이유

많은 사람이 “여러 타입이 들어올 수 있는 값”을 다루려 할 때 dynamic을 떠올립니다. 하지만 실무에서는 종종 Object?를 더 선호합니다. 이유는 안전하게 막아주기 때문입니다.

  • Object?는 “여러 타입이 들어올 수 있다”를 표현하면서도,

  • 그 값을 사용할 때는 캐스팅을 강제해서, 실수 가능성을 줄입니다.

Object o = "hi";
// o.length;            // 컴파일 에러: Object에는 length가 없음
(o as String).length;  // 캐스팅 후 OK

dynamic d = "hi";
d.length;              // 컴파일 OK (대신 런타임 위험)
  • dynamic: 쓰기는 편하지만, 잘못 쓰면 런타임 에러로 이어지기 쉬움

  • Object?: “확실히 확인하고(캐스팅하고) 쓰자”를 강제하는 더 안전한 선택

그래서 var를 설명할 때 dynamicObject?를 같이 묶어 “타입이 불명확한 값 처리”의 관점에서 비교하는 경우가 많습니다.

실전에서 안전하게 쓰는 기준

var가 위험해지는 순간은 거의 정해져 있습니다.

  • 초기값 없는 var x;는 피한다

  • 타입이 불명확한 값(특히 JSON/Map/API 응답)을 받을 때는 dynamic을 남발하지 않는다

  • “뭐가 들어올지 모르는 값”이면 Object?로 받고, 사용할 때 캐스팅/검증을 한다

  • “타입이 확실한 값”이면 var를 써도 안전하다(초기값이 있는 형태로)

결론

var는 “타입을 안 쓰는 문법”이 아니라 “초기값을 보고 타입을 추론해 고정하는 문법”입니다. 따라서 대부분의 경우 var x = 1;처럼 초기값과 함께 쓰면 타입이 명확해지고, 다른 타입의 값이 들어오는 실수를 컴파일 단계에서 막아줘서 안전합니다. 반대로 var x;처럼 초기값 없이 선언하면 추론 근거가 없어 사실상 dynamic처럼 동작할 수 있고, 이때부터는 타입 관련 문제가 실행 중에 드러날 가능성이 커집니다. 또한 “여러 타입이 들어올 수 있는 값”을 다룰 때 dynamic으로 쉽게 흘러가면 편한 대신 런타임 오류 위험이 커지므로, 의도를 더 안전하게 드러내고 싶다면 Object?로 받고 필요한 순간에 캐스팅/검증을 강제하는 방식이 실무에서 더 선호됩니다. 정리하면, var 자체가 위험한 것이 아니라 “타입이 언제 확정되는지”를 놓치고 쓰는 방식이 위험을 만들며, 초기값 기반 추론이 가능한 곳에서는 var, 타입이 불명확한 데이터에서는 Object?/명시적 타입 및 검증을 통해 안전장치를 두는 것이 핵심입니다.

FAQ

var를 쓰면 무조건 dynamic이 되는 건가요?

아닙니다. var x = 1;처럼 초기값이 있으면 xint로 추론되어 고정됩니다. dynamic처럼 동작하는 경우는 대표적으로 var x;처럼 초기값이 없어 타입을 추론할 근거가 없을 때입니다.

var x;가 왜 위험한가요?

초기값이 없으면 타입 추론이 불가능해져, 지역 변수에서는 dynamic처럼 동작하는 구간으로 들어갈 수 있습니다. 그 결과 타입이 섞여 들어오는 실수가 컴파일 단계에서 잘 걸러지지 않고, 실행 중 오류로 이어질 가능성이 커집니다.

dynamic은 언제 써야 하나요?

정말로 “타입이 정해지지 않은 값”을 다뤄야 하거나, 외부 라이브러리/프레임워크 경계에서 불가피하게 동적 처리가 필요할 때 최소 범위로 사용하는 것이 일반적입니다. 편하다는 이유로 넓게 퍼뜨리면 런타임 오류가 늘어나 유지보수가 어려워집니다.

Object?는 dynamic보다 왜 더 안전한가요?

Object?는 어떤 타입이든 담을 수 있지만, 그 값을 사용할 때는 컴파일러가 멤버 접근을 허용하지 않기 때문에 캐스팅이나 타입 체크를 강제합니다. 즉 “확인하고 쓰자”를 코드 수준에서 강제해 실수를 줄여줍니다. 반면 dynamic은 멤버 접근까지 넓게 허용해 오류가 실행 시점으로 밀릴 수 있습니다.

var를 쓰되 안전하게 쓰는 가장 간단한 규칙이 있나요?

있습니다. “초기값이 있으면 var, 초기값 없이 비워둘 거면 명시 타입”이 기본 규칙입니다. 예를 들어 나중에 값을 채울 계획이라면 var x; 대신 int? x;처럼 의도를 드러내는 편이 안전합니다.

JSON이나 API 응답을 받을 때 var를 쓰면 안 되나요?

무조건 안 되는 건 아니지만 주의가 필요합니다. JSON 응답은 구조가 불명확하거나 값 타입이 섞이는 경우가 많아, 무심코 var로 받아 흐름이 dynamic으로 퍼지기 쉽습니다. 이럴 때는 Map<String, dynamic> 또는 더 나아가 모델 클래스로 파싱해 타입을 고정하는 방식이 안정적입니다.

var가 Object?로 “바뀐다”는 표현은 정확한가요?

엄밀히 말하면 var가 자동으로 Object?로 변환되는 문법은 아닙니다. 다만 타입이 불명확한 데이터를 var로 뭉개서 다루다 보면, 결국 “여러 타입이 들어올 수 있다”는 의도를 명확히 하기 위해 Object?로 선언하거나, API/라이브러리에서 Object? 타입으로 값을 받는 상황을 만나게 되는 흐름을 설명하는 표현에 가깝습니다.

var와 타입 명시 중 무엇을 더 많이 쓰는 게 실무에선 맞나요?

둘 다 많이 씁니다. 타입이 명확하고 초기값이 있는 경우에는 var가 간결하고 충분히 안전합니다. 반대로 데이터 구조가 복잡하거나 팀에서 의도를 더 명확히 드러내야 하는 구간, 혹은 nullable/제네릭처럼 타입 정보가 중요한 구간에서는 타입을 명시하는 편이 읽기와 유지보수에 유리합니다.

런타임 오류를 줄이려면 어떤 습관이 가장 효과적인가요?

dynamic이 퍼지지 않도록 경계를 관리하는 습관이 가장 큽니다. 타입이 불명확한 입력(예: JSON)을 받은 직후에 파싱/검증으로 타입을 고정하고, 이후 로직은 고정된 타입으로만 흐르게 만들면 런타임 오류가 크게 줄어듭니다.

댓글 남기기