Dart는 정적 타입을 가지며, Rust, Python, Java, C++, JavaScript와 비교했을 때 특정 문법적 차이와 유사성이 존재한다. Dart를 학습할 때 다음과 같은 문법적 특징을 고려하는 것이 바람직하다.
1. 타입과 변수
Dart는 Java 및 C++처럼 정적 타입(static typing)을 기반으로 한다. 이는 변수 선언 시 명시적인 타입 지정을 요구하지만, 타입 추론(type inference)을 통해
var
키워드를 사용할 경우 변수의 타입을 자동으로 추론할 수 있다. 이는 Python과 JavaScript의 동적 변수 선언 방식과 유사하다.int number = 10; // 명시적 타입 선언 var inferredNumber = 10; // 타입 추론에 의한 int 선언
또한, Dart는 동적 타입(dynamic typing)을 지원하며,
dynamic
키워드를 사용하여 타입의 유연성을 허용한다. 이는 JavaScript의 var
나 Python의 변수 선언과 유사한 방식으로 사용할 수 있다.dynamic variable = 10; variable = "문자열"; // 타입 변경 허용
2. Null Safety
Dart는 안정적인 null 안전성(sound null safety)을 제공하여, 변수가 명시적으로 nullable로 선언되지 않는 한 null 값을 허용하지 않는다. 이는 Rust의
Option<T>
개념과 유사한 방식으로, null 참조로 인한 오류를 방지할 수 있다.String? nullableString; // nullable 변수 선언 String nonNullableString = "Dart"; // non-nullable 변수
3. 함수 선언
Dart는 JavaScript의 화살표 함수(arrow function) 또는 Python의 lambda 함수와 유사한 간결한 함수 선언 방식을 제공한다. 이로 인해 함수의 단일 표현식 구현이 가능하다.
int add(int a, int b) => a + b;
4. 클래스와 객체
Dart의 클래스 구조는 Java와 C++의 클래스 시스템과 유사하나, **선택적 생성자(optional constructor)**와 초기화 목록(initializer list) 등의 기능을 추가적으로 지원한다.
class Person { String name; int age; // 기본 생성자 Person(this.name, this.age); // 명명된 생성자(named constructor) Person.named({required this.name, this.age = 18}); }
5. 비동기 프로그래밍 (Futures와 Streams)
Dart는 비동기 프로그래밍을 위해
Future
를 사용하며, 이는 JavaScript의 async/await
패턴 또는 Rust의 futures
와 유사하다. 또한, 여러 이벤트나 값의 흐름을 처리하기 위한 Stream
도 제공된다.Future<String> fetchData() async { await Future.delayed(Duration(seconds: 2)); return "데이터 수신 완료"; }
6. Mixin과 인터페이스
Dart는 코드 재사용을 위해 믹스인(Mixin)을 지원하며, 이는 Python의 다중 상속이나 Rust의 트레잇(trait)과 유사하다. 인터페이스는 Dart에서 클래스 구현을 통해 지원된다.
mixin Swimmer { void swim() => print("수영 중"); } class Fish with Swimmer {}
7. 선택적 및 명명된 매개변수
Dart는 Python의 위치 기반 선택적 매개변수(positional optional parameters)와 유사한 기능을 제공하며, JavaScript의 객체 형태와 유사한 명명된 매개변수(named parameters)도 지원한다.
void greet(String name, {String? title}) { print('안녕하세요, $title $name'); }
8. 컬렉션 (List, Set, Map)
Dart의 컬렉션(Collection)은 Python과 JavaScript의 리스트(list), 세트(set), 맵(map)과 유사한 구조를 가지며, 리터럴 표현과 간결한 초기화를 지원한다.
List<int> numbers = [1, 2, 3]; Map<String, int> scores = {'Alice': 95, 'Bob': 85};
9. 제어 흐름 및 예외 처리
Dart의 제어 구조는
if
, for
, while
, switch
와 같은 구문을 포함하며, 다른 언어와 유사하다. Dart의 switch-case
는 패턴 매칭을 허용하는 고급 기능을 제공한다.switch (value) { case 1: print('하나'); break; default: print('알 수 없음'); }
void main() { try { int result = 10 ~/ 0; // 0으로 나누기 시도 -> 예외 발생 } catch (e) { print('예외 발생: $e'); // 예외를 처리 } finally { print('이 코드는 예외 발생 여부와 상관없이 실행됩니다.'); } }
10. Const와 Final
Dart에서는
const
와 final
두 가지 키워드를 제공하며, 이는 C++과 Java에서의 상수 선언과 유사하지만, 용도에 차이가 있다. const
는 컴파일 시간 상수를 의미하며, final
은 런타임 상수로 사용된다.const pi = 3.1416; // 컴파일 시간 상수 final now = DateTime.now(); // 런타임 상수
11. 라이브러리와 임포트
Dart는 Python이나 Java처럼 외부 라이브러리를 사용하기 위해
import
구문을 사용한다.import 'dart:math';
12. 메인 함수
Dart 프로그램은 C++, Java, Rust처럼
main()
함수에서 시작된다. 이는 프로그램 진입점을 명확하게 정의한다.void main() { print('Hello, Dart!'); }
13. 연산자 오버로딩 금지
Dart는 C++이나 Rust와 달리 연산자 오버로딩(operator overloading)을 지원하지 않는다. 예외적으로 문자열과 숫자에 대해
+
연산은 허용된다. 이러한 Dart의 문법적 특성을 이해하고, 기존의 다양한 언어들과 비교함으로써 더 효율적으로 Dart를 학습할 수 있다.