Dart 튜토리얼 11편: dart:core & dart:async 실전(문자열·컬렉션·Future/Stream)
요약
핵심 요지
- 문제 정의: 기본 타입(
String1,List2)과 비동기(Future3,Stream4)를 각각 따로 배우면, 실제 코드를 조립할 때 어디서부터 시작해야 할지 막힌다. - 핵심 주장: Dart는 모든 프로그램에 자동으로 포함되는
dart:core5 위에, 비동기 실행을 위한dart:async6를 얹어 “기본 타입 + 비동기 흐름”을 한 언어 경험으로 만든다. - 주요 근거:
print()7 같은 기본 I/O부터int.parse()[^int-parse],RegExp8, 컬렉션 타입, 그리고async9/await10 기반의Future와Stream사용 예시가 함께 제공된다. - 실무 기준: 먼저
dart:core의 문자열/컬렉션 처리 패턴을 잡고, 다음으로Future의 에러 핸들링(catchError()11,whenComplete()12)을 “초기에 등록”하는 습관을 들인다.
문서가 설명하는 범위
dart:core의 문자열/정규식, 숫자 처리, 컬렉션 사용 예시dart:async의Future/Stream개요와async/await스타일Future체인에서의 에러 처리(catchError(),whenComplete()) 패턴과 주의점
읽는 시간: 15분 | 난이도: 초급
참고 자료
- dart
- 문자열/컬렉션/날짜 등 기본 기능 - dart
- Future/Stream, async/await - Futures and error handling - then/catchError/whenComplete 패턴
문제 상황
입문자 입장에서는 “문자열 처리”와 “비동기 처리”가 서로 다른 챕터처럼 보입니다.
하지만 실제 앱 코드는 문자열을 파싱하고, 리스트를 만들고, 네트워크/파일 작업을 기다리는 흐름이 한 함수 안에서 같이 등장합니다.
이 조합을 처음부터 같이 묶어두지 않으면, 코드를 짜다가 Future 체인에서 에러가 사라지거나, Stream을 어디서 받아야 하는지 헷갈릴 수 있습니다.
해결 방법
단계 1: dart:core로 “기본 데이터 처리”를 빠르게 고정하기
Why
NOTE비동기를 배우기 전에, 데이터가 “어떤 형태로 들어오고 나가는지”가 먼저 정리되어야 합니다.
특히 문자열/숫자/컬렉션 처리는 거의 모든 코드의 바닥입니다.print('I drink $tea.');
What
NOTE
dart:core는 모든 Dart 프로그램에 자동으로 포함되는 기본 라이브러리입니다.
문자열, 숫자, 컬렉션 같은 핵심 타입과 기본 함수가 여기에 들어 있습니다.
How
TIP문자열과 숫자 변환은 “파싱 → 검증” 패턴으로 자주 쓰입니다.
assert(int.parse('42') == 42);assert(int.parse('0x42') == 66);assert(double.parse('0.50') == 0.5);// 16진수처럼 radix를 명시할 수도 있다.assert(int.parse('42', radix: 16) == 66);문자열은 검색/분해/치환 패턴이 반복됩니다.
// 포함 여부/시작/끝/인덱스assert('Never odd or even'.contains('odd'));assert('Never odd or even'.startsWith('Never'));assert('Never odd or even'.endsWith('even'));assert('Never odd or even'.indexOf('odd') == 6);// 부분 문자열/분해assert('Never odd or even'.substring(6, 9) == 'odd');var parts = 'progressive web apps'.split(' ');assert(parts.length == 3);// 정규식 치환var greetingTemplate = 'Hello, NAME!';var greeting = greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');assert(greeting != greetingTemplate);
Watch out
WARNING문자열 인덱싱과
codeUnits는UTF-1613 단위로 동작합니다.
즉, “문자 하나 = 인덱스 하나”라고 단정하기 전에, 처리 단위를 먼저 확인해야 합니다.// UTF-16 코드 유닛 리스트를 얻는다.var codeUnitList = 'Never odd or even'.codeUnits.toList();assert(codeUnitList[0] == 78);
결론: dart:core의 기본 패턴(파싱/치환/분해)을 먼저 고정하면, 비동기 코드에서도 데이터 흐름이 흔들리지 않습니다.
단계 2: dart:async의 Future를 “읽기 쉬운 흐름”으로 만들기
Why
NOTE네트워크/파일 작업은 결과가 “나중에” 옵니다.
그래서 코드가 “대기 → 다음 작업” 흐름으로 이어질 수 있어야 합니다.myFunc().then(processValue).catchError(handleError);
What
NOTE
Future는 “나중에 완료되는 작업의 결과”를 표현합니다.
then()14으로 다음 작업을 연결하고,catchError()로 에러 흐름을 처리합니다.
How
TIP
then()체인은 길어지기 쉽습니다.
그래서 같은 흐름을async/await로 바꾸면 읽기가 쉬워집니다.Future<void> runUsingAsyncAwait() async {var entryPoint = await findEntryPoint();var exitCode = await runExecutable(entryPoint, args);await flushThenExit(exitCode);}에러는
try/catch로 한 덩어리로 묶을 수 있습니다.var entryPoint = await findEntryPoint();try {var exitCode = await runExecutable(entryPoint, args);await flushThenExit(exitCode);} catch (e) {// 예외를 처리한다.}
Watch out
WARNING에러 핸들러 등록이 늦으면, 에러가 이미 발생한 뒤라 잡지 못할 수 있습니다.
즉,Future를 만든 뒤 “나중에”catchError()를 붙이는 패턴은 피하는 편이 안전합니다.Future<Object> future = asyncErrorFunction();// 나쁜 예: 에러 핸들러 등록이 너무 늦다.Future.delayed(const Duration(milliseconds: 500), () {future.then(...).catchError(...);});
결론: Future는 “읽기 쉬운 연결”과 “빠른 에러 처리 등록”이 핵심입니다.
단계 3: Future 체인의 에러 처리 패턴을 “결과/정리”까지 포함해 완성하기
Why
NOTE실패가 나면 “로그를 남기고 끝”이 아니라, 연결된 후속 작업의 진행 여부와 자원 정리까지 결정해야 합니다.
그래서catchError()와whenComplete()를 함께 보는 편이 좋습니다.final server = connectToServer();server.post(myUrl, fields: const {'name': 'Dash', 'profession': 'mascot'}).then(handleResponse).catchError(handleError).whenComplete(server.close);
What
NOTE
catchError()는 에러를 처리하거나 값을 반환해 흐름을 이어갈 수 있습니다.
whenComplete()는 성공/실패와 무관하게 실행할 “마무리 작업”을 등록합니다.
How
TIP아래 예시는 중간에 에러가 나면
catchError()로 값을 만들어 “다음 then”을 계속 진행합니다.Future<String> one() => Future.value('from one');Future<String> two() => Future.error('error from two');Future<String> three() => Future.value('from three');Future<String> four() => Future.value('from four');void main() {one().then((_) => two()).then((_) => three()).then((_) => four()).then((value) => value.length).catchError((e) {print('Got error: $e');return 42;}).then((value) {print('The value is $value');});}
Watch out
WARNING
then()의onError와catchError()를 섞을 때는, “어느 에러가 어디로 흘러가는지”가 헷갈릴 수 있습니다.
특히then(..., onError: ...)안에서 또 다른 비동기 함수를 호출하면, 그 에러는 뒤의catchError()로 넘어갈 수 있습니다.asyncErrorFunction().then(successCallback,onError: (e) {handleError(e); // 원래 에러anotherAsyncErrorFunction(); // 여기서 생긴 새 에러},).catchError(handleError);
결론: Future 에러 처리는 “흐름을 계속할지/멈출지”와 “항상 정리할지”까지 함께 결정해야 합니다.
Footnotes
-
String(스트링): 문자열을 표현하는 타입이다. ↩
-
List(리스트): 순서가 있는 컬렉션 타입이다. ↩
-
Future(퓨처): 나중에 완료되는 작업의 결과를 표현하는 타입이다. ↩
-
Stream(스트림): 시간이 지나면서 여러 이벤트/값이 들어오는 흐름을 표현하는 타입이다. ↩
-
dart
(dart ): 모든 Dart 프로그램에 자동으로 포함되는 핵심 라이브러리다. ↩ -
dart
(dart ): Future/Stream 등 비동기 기능을 제공하는 라이브러리다. ↩ -
print()(프린트): 객체의 문자열 표현을 콘솔에 출력하는 함수다. ↩
-
RegExp(정규식): 문자열 패턴을 표현하는 정규식 타입이다. ↩
-
whenComplete()(웬 컴플리트): 성공/실패와 무관하게 실행할 마무리 작업을 등록하는 메서드다. ↩
-
UTF-16(UTF-16): 문자열을 16비트 단위 코드 유닛으로 표현하는 문자 인코딩 방식이다. ↩
공유
이 글이 도움이 되었다면 다른 사람과 공유해주세요!