Flutter + Dart/Flutter + Dart TIP
Dart(및 Flutter) 언어에서 사용되는 주요 키워드/수식어(modifier)/식별자(reserved identifiers)
GREEN나무
2025. 5. 16. 11:34
728x90
아래 표는 Dart(및 Flutter) 언어에서 사용되는 주요 키워드·수식어(modifier)·식별자(reserved identifiers)를 분류별로 정리한 것입니다. 각 항목별 간단한 설명과 예시 코드도 함께 제공합니다.
1. 선언·수정자(Declaration Modifiers)
키워드 | 설명 | 예시 코드 |
abstract | 추상 클래스/메서드 선언 | abstract class Animal { void speak(); } |
const | 컴파일 타임 상수 | static const pi = 3.14; |
final | 런타임 상수 (한 번 할당 후 변경 불가) | final name = 'Flutter'; |
late | 지연 초기화 (나중에 한 번만 할당) | late String description; |
external | 구현부가 네이티브 라이브러리 등 외부에 있음을 표시 | external void nativeFunction(); |
factory | 팩토리 생성자 선언 | class A { factory A() => A._(); A._(); } |
static | 클래스 레벨(정적) 멤버 선언 | static const version = '1.0'; |
typedef | 함수 또는 제네릭 타입 별칭 선언 | typedef Callback = void Function(int); |
var | 타입 추론 변수 선언 | var count = 3; |
dynamic | 런타임 타입 검사 변수 | dynamic anything = 'text'; |
void | 반환값이 없음을 표시 | void runApp() { /*...*/ } |
required | named parameter를 필수로 표시 | void fn({required int id}) {} |
covariant | 파라미터를 하위 타입 허용 | void set value(covariant num v) {} |
2. 클래스·믹스인·인터페이스 관련
키워드 | 설명 | 예시 코드 |
class | 클래스 선언 | class Person { String name; } |
extends | 상속 | class Student extends Person { int grade; } |
implements | 인터페이스(다중) 구현 | class Dog implements Animal { void speak() {} } |
with | 믹스인 사용 | class Bird with Flyable {} |
mixin | 믹스인 선언 | mixin Flyable { void fly() {} } |
enum | 열거형 타입 선언 | enum Color { red, green, blue } |
extension | 기존 타입에 메서드 추가 | extension StrUtils on String { bool get isEmpty_ => this.isEmpty; } |
3. 라이브러리·모듈 관리
키워드 | 설명 | 예시 코드 |
import | 다른 라이브러리 가져오기 | import 'package:flutter/material.dart'; |
export | 다른 라이브러리를 재노출 | export 'src/utils.dart'; |
library | 라이브러리 파일 그룹 정의 | library my_library; |
part | 라이브러리의 파트 파일 포함 | part 'src/part_a.dart'; |
part of | 해당 파트가 소속된 라이브러리 지정 | part of my_library; |
show | import/ export 시 특정 멤버만 노출 | import 'dart:math' show pi, sqrt; |
hide | import/ export 시 특정 멤버만 숨김 | import 'dart:math' hide Random; |
deferred | 지연 로딩(import) | import 'package:heavy.dart' deferred as heavy; |
4. 흐름 제어(Control Flow)
키워드 | 설명 | 예시 코드 |
if / else | 조건 분기 | if (x>0) print('양수'); else print('음수'); |
switch | 다중 분기 | switch(c){ case 1: break; default:} |
case / default | switch 내 분기 | switch(color) { case Color.red: break; } |
for | 반복문 | for(var i=0;i<3;i++) print(i); |
while | while (!done) { /*...*/ } | |
do...while | 후조건 반복 | do { work(); } while(!done); |
break | 루프 또는 switch 탈출 | |
continue | 루프의 다음 반복으로 이동 | |
return | 함수/메서드 반환 | int sum() => 0; |
try / catch / finally | 예외 처리 | try { risky(); } catch(e) {} finally {} |
throw | 예외 발생 | throw Exception(); |
rethrow | 캐치된 예외 재발생 | catch(e) { rethrow; } |
assert | 디버그 모드 검증 | assert(value!=null); |
5. 비동기·생성기(Async & Generator)
키워드 | 설명 | 예시 코드 |
async | 비동기 함수 선언 | Future fetch() async { await api(); } |
await | Future 완료 대기 | |
async* | 비동기 생성기 | Stream<int> gen() async* { yield 1; } |
sync* | 동기 생성기 | Iterable<int> gen2() sync* { yield* [2,4]; } |
yield | 생성기 단일 값 방출 | |
yield* | 다른 Iterable/Stream 전체 방출 |
6. 기타 식별자·연산자 관련
키워드 | 설명 | 예시 코드 |
as | 타입 캐스트 / 네임스페이스 별칭 | value as String; import 'a.dart' as a; |
is | 타입 검사 | if(obj is Person){} |
in | for-in 루프 | for(var ch in 'abc'.split('')){} |
operator | 연산자 오버로딩 | A operator +(A o)=>this; |
get / set | 게터/세터 선언 | int get x=>_x; set x(int v){_x=v;} |
new | 객체 생성 (선택적) | var o=new Object(); |
this | 인스턴스 자신 참조 | print(this.name); |
super | 부모 클래스 참조 | super.toString(); |
on | 믹스인 제약 or 이벤트 핸들러 메서드 지정 | extension E on String{} |
covariant | 하위 타입 허용 파라미터 표시 | void set value(covariant num v) {} |
required | null-safety에서 필수 named parameter 표시 | void fn({required int id}) {} |
never | 결코 반환하지 않는 함수의 반환 타입(Never) | Never throwError() { throw Error(); } |
7. 리터럴·상수 값
키워드 | 설명 | 예시 코드 |
true | 불리언 상수 true | bool ok = true; |
false | 불리언 상수 false | bool ng = false; |
null | null 값 | String? s = null; |
1. 선언 키워드별 차이와 활용
- var vs final vs const vs dynamic
- var x = 3; → int로 추론, 재할당 가능
- final x = 3; → 런타임에 한 번만 초기화, 재할당 불가
- const x = 3; → 컴파일 타임 상수, 인스턴스 공유
- dynamic x = 3; → 타입 검사 런타임 수행, 유연하지만 안정성 ↓
- 언제 타입 명시?
- 공개 API의 파라미터/리턴
- 제네릭·복잡 타입
- 가독성 위해
2. final String label;, final VoidCallback onTap; 설명
- 위젯 프로퍼티로, 생성자 초기화 후 불변
- VoidCallback = void Function() 타입 별칭
- 예시
class MyButton extends StatelessWidget { final String label; final VoidCallback onTap; const MyButton({required this.label, required this.onTap, Key? key}): super(key:key); @override Widget build(BuildContext c) => GestureDetector(onTap:onTap,child:Text(label)); }
3. final String todo = 'do something'; 에 키워드가 두 개 들어간 이유
- final = 수정자(modifier), 런타임 상수
- String = 타입 지정(key type)
- 타입 생략 시: final todo = 'do something'; → String으로 추론
4. const 위젯 vs final 프로퍼티
- const 생성자
- 컴파일 타임에 완전 불변이라는 것을 Dart가 보장
- 위젯 트리에서 동일한 인스턴스를 재사용해 메모리·성능 최적화
- 조건
- 모든 필드가 final이어야 하고,
- 생성자 인자로 전달되는 값도 const여야 함
- 언제 사용하나?
- UI가 전혀 변하지 않을 때 (예: 아이콘, 단순 텍스트 위젯)
- 반복해서 그리는 작은 위젯(리스트 아이템, 버튼 등)의 부모에 const를 붙이면 하위 전체를 재빌드하지 않음
- final 프로퍼티
- 런타임에 한 번만 할당하고 이후 변경 불가
- 인자값이 런타임에 결정될 때(네트워크 응답, 사용자 입력 등)
- 언제 사용하나?
- 생성자에 required this.value 형태로 넣되, 값이 const가 아닐 때
- StatefulWidget에서 initState 내에서 초기화해야 할 때
// const 쓰기 좋은 예
class StaticLabel extends StatelessWidget {
const StaticLabel({Key? key}) : super(key: key);
@override Widget build(_) => const Text('앱 이름');
}
// final 써야 하는 예
class UserBadge extends StatelessWidget {
final String userName;
const UserBadge({required this.userName, Key? key}): super(key: key);
@override Widget build(_) => Text(userName);
}
5. 타입 명시 컨벤션
- 로컬 변수 생략 (타입 추론)
- var count = 0; → int로 추론
- 읽기 쉽고 코드 양 감소
- 적합할 때:
- 복잡하지 않은 숫자·문자열·컬렉션
- 테스트 코드·샘플 코드처럼 가독성을 우선할 때
- 공개 API만 명시
- void fetchData(List<String> ids) 처럼 외부 사용자가 보는 함수 시그니처에 타입을 명시
- 장점: 문서화 효과, 동적 리팩토링 시 안정성
- 추천 가이드라인
- 프로젝트/팀 스타일 가이드 채택
- public API: 항상 타입 명시
- private·로컬: 간단한 경우 var/추론, 복잡·제네릭이면 명시
6. late 초기화 이슈 경험과 대처
- 주요 오류:
- LateInitializationError: Field 'xxx' has not been initialized.
- 순서상 initState 전에 접근했거나, 초기화 조건문 내에서만 할당해 호출 시점에 누락
- 원인 분석
- StatefulWidget의 build에서 곧바로 참조
- 비동기 로직 완료 전 접근
- 해결책
- nullable 타입로 변경 후 null 체크
- late String? data; if (data != null) Text(data!);
- 초기화 보장 패턴
- 생성자 초기화 리스트
- initState에서 초기화 후 setState로 알림
- 커스텀 Getter로 지연 초기화
- String get config => _config ??= loadConfig(); String? _config;
핵심 요약
- 변수 선언:
- var → 재할당 가능, 타입 추론
- final → 런타임에 한 번만 초기화
- const → 컴파일 타임 상수, 인스턴스 공유
- dynamic → 런타임 타입 검사, 유연하지만 안정성↓
- 타입 명시:
- 공개 API(파라미터·리턴) → 항상 명시
- 로컬·단순 변수 → var/추론, 복잡할 땐 명시
- 위젯 불변성:
- const 생성자 → 모든 필드 final, 인자도 const일 때
- final 프로퍼티 → 런타임 값 필요 시
- late 초기화:
- 주의: 초기화 전 접근 시 LateInitializationError
- 해결: nullable+체크, 생성자·initState 초기화, 커스텀 Getter 활용