Dart

2023년 8월 8일 수정

이 글은 다트(Dart) 프로그래밍 언어의 소개 및 간단한 문법 등을 정리하는 글이다.

Dart

구글이 개발한 프로그래밍 언어다. 그래서 구글이 아니면 잘 안 쓴다. 그런데 구글에서도 Flutter를 제외하면 거의 안 쓴다.

네이티브 코드가 아니라 VM(Virtual Machine) 위에서 돌아간다. 컴퓨팅 자원을 낭비하는 정말 최악의 특징이다. 문법적으로 줄 끝에 세미콜론을 찍어야 하는 빌어먹을 특징까지 가지고 있다.

그 외에 async - await 등 다양한 부분에서 Javascript와 유사한 점이 종종 보이는 것 같다.

그나마 다행인 점은 정적 타이핑 언어라는 점이다.

개인적으로 싫어하는 언어이지만 써야 하기 때문에 억지로 남기는 메모가 이어진다.

엔트리 포인트(Entry Point)

void main() {
  print('Hello World!');
}

C와 비슷하지만 print 함수가 자동으로 개행 문자를 붙인다는 점에서 다르다. 반환 타입도 없는데 *NIX 와는 어울리지 않겠다는 의미로 보면 될까?

참고로 문자열 표현은 Javascript와 비슷하게 따옴표와 쌍 따옴표 둘 다 이용할 수 있다.

타입(Types)

타입 체크

인스턴스의 타입이 무엇인지 확인하기 위해서 Python과 비슷하게 is 를 사용할 수 있다.

instance is Type

문자열 조합(String Interpolation)

print('foo is $foo');

만약 클래스 프로퍼티나 특정 구문의 실행 결과를 문자열에 넣으려면 중괄호로 감싸주면 된다.

print('foo bar is ${foo.bar}');

함수(Function)

함수를 정의하는 몇 가지 예를 보자.

someProcedure() {
  // ...
}

anotherProcedure(value) {
  print('$value');
}

fooLambda() => print('blah blah');

bool isOdd(value) {
  return value % 2 != 0;
}

String nameCard({name: String, age: int}) {
  return '$name, $age';
}

반환 타입이 없는 것은 그냥 void 타입 함수라고 생각하자.

화살표 함수는 Javascript의 것과 상당히 유사하다. 아예 return 이 생략되어 있는 형태인 점도 잘 생각해두자.

마지막 함수의 매개 변수 선언하는 쪽에는 중괄호가 둘러싸고 있는데, named field 형태를 구현하는 방법으로 역시 빌어먹을 Javascript에서 쓰는 방법과 유사하다. 아니 언어를 새로 만드는 데 이딴 것도 그냥 문법으로 새로 만들면 되잖아? 이해가 안 되네.

루프(Loop)

기본적은 for-loop 모양은 C 식과 거의 동일하다.

for (int i=0; i < 5; i++) {
  print('current = $i');
}

forEach 는 아래와 같이 리스트와 섞어서 쓰면 편하다.

// ['alpha', 'beta', 'gamma'].forEach((e) => print(e));
['alpha', 'beta', 'gamma'].forEach((e) {
    print(e);
});

Map과 Filter

Map은 리스트에 그냥 쓰면 된다.

[1, 2, 3].map((e) => 'number $e');

그런데 Filter는 좀 다른 것 같다.

[1, 2, 3, 4, 5].where((e) => e % 2 == 0).toList()

where() 의 결과는 반복 가능한 타입이라 바로 iteration 해도 상관은 없는데, 일반 리스트로 얻기 원한다면 toList() 로 변환해 줘야 한다. 즉, where 자체가 filter와 동일하다고 볼 수 있다.

클래스(Class)

기본 형태

기본적인 모양은 이런 식이다.

class SomeClass extends SomeParentClass {
  // Property and Default Value
  String name = 'Conrad';

  // Constructor
  SomeClass(String anotherName) {
    name = anotherName;
  }

  // Named Constructor
  SomeClass.anonymous() {
    name = 'Nonamed Who';
  }

  // Method
  void whoami() {
    print('I am $name');
  }

  // Method - usage of 'this'
  void updateName(String name) {
    this.name = name;
  }

  ...

  // override method
  @override
  void nag() {
    super.nag()
    ...
  }
}

상속에 오버라이드에 생성자 패턴에 뭐 기본적인 사항은 다 있는 것 같다.

Setter 그리고 Getter

class SomeClass extends SomeParentClass {
  int age = 0;
  ...

  // bool get koreanAge {
  //   return age + 1;
  // }
  bool get koreanAge => this.age + 1;

  set koreanAge(int korAge) {
    this.age = korAge - 1;
  }
}

화살표 함수 형태를 쓰면 역시 단축이 가능하다.

콜백(Callback)

Function 키워드를 이용하면 콜백 함수 프로퍼티를 선언할 수 있다.

Function(int param1, String param2)? onSomeAction;

패러미터가 없다면 아예 괄호 전체를 없애버려도 관계는 없다.

콜백 핸들러를 정의하는 방법은 기존대로 하면 된다.

onSomeAction = (param1, param2) => {
  ...
}

위는 클로저 문법으로 콜백 핸들러를 구현했다. 물론 정적 함수나 메서드로 구현해서 심볼을 넘겨줘도 잘 동작한다.

추가로 리턴 값이나 패러미터가 필요 없다면 VoidCallback 을 사용할 수도 있다.

VoidCallback? onSomeAction;

Dart 베타 버전 (with Homebrew)

Homebrew를 사용한다면 베타 채널로 쉽게 스위칭이 가능하다.

brew install dart-beta

다만 기존에 dart가 설치되어 있다면 기존 것을 unlink 해야 한다.

brew unlink dart

안정 버전으로 되돌릴 때는 dart-beta 를 unlink하고 dart 를 다시 링크하면 된다.

brew unlink dart-beta
brew link dart