Flutter 튜토리얼 3편: Flutter를 위한 Dart 기초

요약#

핵심 요지#

  • 문제 정의: Flutter는 Dart 언어를 사용하므로, Dart를 모르면 Flutter 코드를 이해할 수 없다.
  • 핵심 주장: Dart는 C 계열 문법과 null safety1를 갖춘 언어로, 기존 언어 경험이 있다면 빠르게 배울 수 있다.
  • 주요 근거: 타입 추론, null safety, async/await2가 Flutter 개발의 핵심이다.
  • 실무 기준: Language Tour로 시작해서 실제 Flutter 코드를 작성하며 익힌다.
  • 한계: Dart 전문가가 될 필요는 없지만, 기초 문법은 반드시 알아야 한다.

문서가 설명하는 범위#

  • Flutter 개발에 필요한 Dart 핵심 개념
  • Dart의 타입 시스템과 null safety
  • 비동기 프로그래밍 기초
  • Dart 학습 리소스와 권장 순서

읽는 시간: 12분 | 난이도: 초급


참고 자료#


문제 상황#

Flutter 앱을 만들려면 Dart 언어로 코드를 작성해야 합니다.
Dart를 모르면 Flutter 코드가 무슨 의미인지 이해할 수 없습니다.
그렇다면 Dart는 어떤 언어일까요?

Dart 없이 Flutter를 배우려는 시도#

// 이 코드가 무슨 뜻인지 모르면 Flutter를 배울 수 없다
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(child: Text('Hello')),
),
);
}
}

문제는 다음과 같습니다.

  • class, extends, const, @override 등 키워드의 의미를 모른다.
  • Widget build(BuildContext context)가 무슨 뜻인지 모른다.
  • ?! 같은 null safety 문법이 낯설다.
  • async, await, Future 같은 비동기 개념이 어렵다.

해결 방법#

Dart는 Java, JavaScript, C++과 비슷한 문법을 사용합니다.
중괄호 {}로 코드 블록을 만들고, 세미콜론 ;으로 문장을 끝내는 방식이죠.
다른 프로그래밍 언어를 배운 적이 있다면 금방 익숙해질 겁니다.

챕터 1: Dart 언어의 특징 이해하기#

Why#

NOTE

Flutter가 왜 Dart를 선택했는지 알면 학습 동기가 생깁니다.
Dart는 UI 개발에 최적화된 언어입니다.
왜 그럴까요?

Dart의 장점
├── 빠른 개발: hot reload 지원
├── 빠른 실행: AOT 컴파일로 네이티브 성능
├── 타입 안전: 컴파일 타임 오류 검출
└── null safety: 런타임 null 오류 방지

What#

NOTE

Dart는 Google이 개발한 프로그래밍 언어입니다.
스마트폰 앱처럼 사용자가 직접 만지는 프로그램을 만들기 좋게 설계되었습니다.
문법은 Java나 JavaScript와 비슷해서 배우기 쉽습니다.

How#

TIP

Dart의 핵심 특징

특징설명예시
타입 안전정적 타입 검사int count = 0;
타입 추론타입 자동 결정var name = 'Flutter';
null safetynull 가능성 명시String? nullable;
비동기 지원async/awaitawait fetchData();

기본 문법 예시

// 변수 선언
int count = 0; // 타입 명시
var name = 'Flutter'; // 타입 추론
final pi = 3.14; // 한 번만 할당
const gravity = 9.8; // 컴파일 타임 상수
// 함수 정의
String greet(String name) {
return 'Hello, $name!';
}
// 클래스 정의
class Person {
final String name;
final int age;
Person(this.name, this.age);
void introduce() {
print('저는 $name이고, $age살입니다.');
}
}

Watch out#

WARNING

Dart는 JavaScript와 비슷해 보이지만 중요한 차이점이 있습니다.

// JavaScript와 다른 점
// 1. 세미콜론 필수
var name = 'Dart'; // ✓ 세미콜론 있음
// var name = 'Dart' // ✗ 오류
// 2. 타입 안전
int count = 0;
// count = 'hello'; // ✗ 타입 오류
// 3. single/double quote 동일
var a = 'hello';
var b = "hello"; // 둘 다 String

결론: Dart는 C 계열 언어 경험이 있다면 빠르게 익힐 수 있습니다.


챕터 2: null safety 이해하기#

Why#

NOTE

null3은 “값이 없음”을 나타냅니다.
문제는 null인 변수를 사용하려고 하면 프로그램이 멈춘다는 거예요.
Dart의 null safety는 이런 실수를 미리 잡아줍니다.

// null safety가 없던 시절
String name = null; // 허용됨
print(name.length); // 런타임 오류!
// null safety 적용 후
String name = null; // 컴파일 오류!

What#

NOTE

null safety는 변수가 null이 될 수 있는지를 미리 정하는 기능입니다.
String이라고 쓰면 “이 변수는 절대 null이 아니야”라는 뜻이고요.
String?처럼 물음표를 붙이면 “이 변수는 null일 수도 있어”라는 뜻입니다.

How#

TIP

nullable과 non-nullable

// non-nullable: null 불가
String name = 'Flutter';
// name = null; // 컴파일 오류
// nullable: null 가능
String? nickname; // 기본값 null
nickname = 'F';
nickname = null; // OK

null 체크 방법

String? name = getName();
// 방법 1: if 조건문
if (name != null) {
print(name.length); // name이 String으로 승격됨
}
// 방법 2: null-aware 연산자
print(name?.length); // null이면 null 반환
print(name ?? 'Unknown'); // null이면 기본값 사용
print(name!.length); // null이 아님을 단언 (위험)

클래스에서 null safety

class Package {
final String name; // 필수 (non-nullable)
final String version; // 필수 (non-nullable)
final String? description; // 선택 (nullable)
Package(this.name, this.version, {this.description});
}
// 사용
var pkg = Package('flutter', '3.38.1');
var pkg2 = Package('dart', '3.7.0', description: 'Dart SDK');
타입null 가능사용 시 체크 필요
String불필요
String?필요
int불필요
int?필요

Watch out#

WARNING

! 연산자는 null이 아님을 단언하지만, 실제로 null이면 런타임 오류가 발생합니다.

String? name = null;
print(name!.length); // 런타임 오류: Null check operator used on a null value
// 안전한 방법
if (name != null) {
print(name.length);
}
// 또는
print(name?.length ?? 0);

결론: null safety로 null 관련 오류를 컴파일 타임에 잡을 수 있습니다.


챕터 3: 비동기 프로그래밍 이해하기#

Why#

NOTE

인터넷에서 데이터를 가져오거나 파일을 읽는 작업은 시간이 걸립니다.
만약 이 작업이 끝날 때까지 기다리면 어떻게 될까요?
앱이 멈춘 것처럼 보입니다.
그래서 비동기 프로그래밍이 필요합니다.

// 동기 방식 (앱이 멈춤)
var data = fetchDataSync(); // 3초 대기
print(data); // 3초 후 실행
// 비동기 방식 (앱이 멈추지 않음)
fetchDataAsync().then((data) {
print(data); // 데이터 준비되면 실행
});
// 즉시 다음 코드 실행

What#

NOTE

Future4는 “나중에 결과가 올 거야”라는 약속입니다.
asyncawait를 사용하면 복잡한 비동기 코드를 간단하게 작성할 수 있습니다.
마치 순서대로 실행되는 코드처럼요.

How#

TIP

async/await 사용법

// Future를 반환하는 함수
Future<String> fetchUserName() async {
// 네트워크 요청 시뮬레이션
await Future.delayed(Duration(seconds: 1));
return 'Flutter Developer';
}
// await로 결과 기다리기
void main() async {
print('요청 시작');
String name = await fetchUserName();
print('이름: $name');
print('요청 완료');
}
// 출력:
// 요청 시작
// (1초 후)
// 이름: Flutter Developer
// 요청 완료

HTTP 요청 예시

import 'package:http/http.dart' as http;
import 'dart:convert';
Future<Map<String, dynamic>> fetchUser(int id) async {
final response = await http.get(
Uri.parse('https://api.example.com/users/$id'),
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Failed to load user');
}
}

에러 처리

Future<void> loadData() async {
try {
final data = await fetchData();
print(data);
} catch (e) {
print('오류 발생: $e');
}
}

Watch out#

WARNING

awaitasync 함수 안에서만 사용할 수 있습니다.

// 잘못된 사용
void main() {
String name = await fetchUserName(); // 오류: await in non-async function
}
// 올바른 사용
void main() async {
String name = await fetchUserName(); // OK
}
// 또는 then 사용
void main() {
fetchUserName().then((name) {
print(name);
});
}

결론: async/await로 비동기 작업을 동기 코드처럼 간결하게 작성할 수 있습니다.


챕터 4: 클래스와 생성자 이해하기#

Why#

NOTE

Flutter의 모든 Widget은 클래스입니다.
클래스가 뭔지 모르면 Flutter 코드를 읽을 수 없습니다.
클래스는 생각보다 어렵지 않습니다.

// Flutter Widget은 모두 클래스
class MyWidget extends StatelessWidget {
// ...
}

What#

NOTE

클래스는 관련된 데이터와 기능을 하나로 묶은 것입니다.
예를 들어 “사람” 클래스에는 이름, 나이 같은 데이터와 인사하기 같은 기능이 있을 수 있죠.
Flutter의 Widget도 이런 클래스로 만들어져 있습니다.

How#

TIP

클래스 기본 구조

class Person {
// 필드 (인스턴스 변수)
String name;
int age;
// 생성자
Person(this.name, this.age);
// 메서드
void introduce() {
print('저는 $name이고 $age살입니다.');
}
}
// 사용
var person = Person('김철수', 30);
person.introduce();

명명된 매개변수 (Named Parameters)

class Button {
final String text;
final double width;
final double height;
// 명명된 매개변수 (중괄호 사용)
Button({
required this.text, // 필수
this.width = 100, // 기본값
this.height = 50, // 기본값
});
}
// 사용 (순서 상관없음)
var btn1 = Button(text: 'Click');
var btn2 = Button(text: 'Submit', width: 200, height: 60);

상속과 오버라이드

class Animal {
void speak() {
print('...');
}
}
class Dog extends Animal {
@override
void speak() {
print('멍멍!');
}
}
class Cat extends Animal {
@override
void speak() {
print('야옹!');
}
}

Flutter Widget 예시

class MyButton extends StatelessWidget {
final String label;
final VoidCallback onPressed;
const MyButton({
super.key,
required this.label,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Text(label),
);
}
}

Watch out#

WARNING

const 생성자는 컴파일 타임 상수를 만들 때 사용합니다. 모든 필드가 final이어야 const 생성자를 사용할 수 있습니다.

class Point {
final int x;
final int y;
const Point(this.x, this.y); // const 생성자
}
// const 인스턴스 (동일 값이면 같은 객체)
const p1 = Point(0, 0);
const p2 = Point(0, 0);
print(identical(p1, p2)); // true
// 일반 인스턴스 (항상 새 객체)
var p3 = Point(0, 0);
var p4 = Point(0, 0);
print(identical(p3, p4)); // false

결론: 클래스와 생성자 문법을 알면 Flutter Widget 코드를 이해할 수 있습니다.


챕터 5: Flutter 앱의 진입점 이해하기#

Why#

NOTE

모든 Dart 프로그램은 main() 함수에서 시작합니다.
Flutter 앱도 마찬가지입니다.
main()에서 runApp()을 호출하면 앱이 시작됩니다.

void main() {
runApp(const MyApp());
}

What#

NOTE

runApp()5은 Flutter 앱을 실행하는 함수입니다.
이 함수에 전달한 Widget이 앱의 첫 화면이 됩니다.
모든 Flutter 앱은 이렇게 시작합니다.

How#

TIP

기본 진입점 구조

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: HomePage(),
);
}
}

초기화 작업이 필요한 경우

void main() async {
// Flutter 엔진 초기화 (비동기 작업 전 필수)
WidgetsFlutterBinding.ensureInitialized();
// 비동기 초기화 작업
await Firebase.initializeApp();
await loadSettings();
runApp(const MyApp());
}
flowchart TD A[main 함수 시작] --> B{초기화 필요?} B -->|예| C[WidgetsFlutterBinding.ensureInitialized] C --> D[비동기 초기화 작업] D --> E[runApp 호출] B -->|아니오| E E --> F[Widget 트리 렌더링]

Watch out#

WARNING

비동기 초기화를 하려면 WidgetsFlutterBinding.ensureInitialized()를 먼저 호출해야 합니다.

// 잘못된 순서
void main() async {
await Firebase.initializeApp(); // 오류 가능!
runApp(const MyApp());
}
// 올바른 순서
void main() async {
WidgetsFlutterBinding.ensureInitialized(); // 먼저 호출
await Firebase.initializeApp(); // 그 다음 초기화
runApp(const MyApp());
}

결론: main()runApp()이 Flutter 앱의 시작점입니다.


챕터 6: Dart 학습 리소스 활용하기#

Why#

NOTE

Dart 전문가가 될 필요는 없습니다.
하지만 기초 문법은 반드시 알아야 합니다.
어디서 배울 수 있을까요?
공식 문서가 가장 좋은 학습 자료입니다.

What#

NOTE

Dart 공식 사이트에는 체계적인 학습 자료가 있습니다.
그중에서 Language Tour가 가장 좋은 시작점입니다.
Dart의 모든 문법을 예제와 함께 설명해줍니다.

How#

TIP

권장 학습 순서

순서자료내용소요 시간
1Language TourDart 문법 전체2-3시간
2Library Tour핵심 라이브러리1-2시간
3Effective Dart스타일 가이드1시간
4비동기 코드랩Future, Stream1시간

Language Tour에서 배울 것

  • 변수와 타입
  • 함수와 클래스
  • null safety
  • 제어문과 반복문
  • 예외 처리
  • 비동기 프로그래밍

JavaScript 개발자라면

JavaScript를 알고 있다면 더 빨리 배울 수 있습니다.
JavaScript to Dart에서 두 언어의 차이점을 확인해보세요.

Watch out#

WARNING

Dart를 완벽하게 배운 다음에 Flutter를 시작하려고 하지 마세요.
그러면 시간이 너무 오래 걸립니다.
기초 문법만 익히고 Flutter를 시작하세요.
필요할 때마다 Dart를 더 배우면 됩니다.

권장 학습 흐름:
1. Dart 기초 (변수, 함수, 클래스) - 2시간
2. Flutter 시작 (첫 앱 만들기) - 1시간
3. 필요할 때 Dart 추가 학습 - 지속

결론: Language Tour로 기초를 익히고, Flutter를 하면서 Dart를 더 배웁니다.


한계#

이 문서는 Flutter 개발에 필요한 Dart 기초만 다룹니다.
더 깊은 내용은 별도로 학습이 필요합니다.

  • 고급 Dart 기능: 제네릭, 믹스인, 익스텐션 등은 별도 학습이 필요합니다.
  • Dart 전용 개발: CLI 앱, 서버 개발 등은 이 문서의 범위가 아닙니다.
  • 심화 비동기: Stream, Isolate 등은 이후 튜토리얼에서 다룹니다.

Footnotes#

  1. null safety(널 안전성): 변수가 null이 될 수 있는지를 타입으로 명시하여 null 관련 오류를 컴파일 타임에 잡는 기능이다.

  2. async/await(비동기 대기): 비동기 작업을 동기 코드처럼 순차적으로 작성할 수 있게 해주는 문법이다.

  3. null(널): 값이 없음을 나타내는 특수한 값이다.

  4. Future(퓨처): 비동기 작업의 결과를 나타내는 객체로, 작업이 완료되면 값을 반환한다.

  5. runApp(런앱): Flutter 앱을 시작하는 함수로, 전달받은 Widget을 화면에 렌더링한다.

공유

이 글이 도움이 되었다면 다른 사람과 공유해주세요!

Flutter 튜토리얼 3편: Flutter를 위한 Dart 기초
https://moodturnpost.net/posts/flutter/flutter-dart-intro/
작성자
Moodturn
게시일
2026-01-08
Moodturn

목차