반응형

https://dart.dev/guides/language/language-tour

 

A tour of the Dart language

A tour of all the major Dart language features.

dart.dev

 

 

위 문서로 공부하며 기억해둘만한 내용만 정리

https://dartpad.dev/

 

DartPad

 

dartpad.dev

실습 사이트

 

부가적인 내용이나 다른 코드가 섞여있을 수 있습니다.

 

 

- 비동기 지원

Dart 라이브러리는 Future와 Stream을 반환하는 함수로 가득하다.

이 함수들은 비동기로 동작한다.

즉, I/O와 같이 시간이 오래 걸래는 작업을 설정한 후, 완료될 때까지 기다리지 않고 반환한다.

async와 await 키워드는 비동기 프로그래밍을 지원하고, 이를 이용하여 동기 코드와 유사한 비동기 코드를 작성할 수 있다.

 

 

- Future 다루기

완료된 Future의 결과가 필요한 경우, 두 가지 선택지가 있다.

async와 await을 사용하거나, Future API를 사용하는 것이다. 

 

async와 await을 사용하는 코드는 비동기지만, 동기 코드와 유사하다.

다음 코드는 await을 사용하여 비동기 함수의 결과를 기다린다.

await lookUpVersion();

 

await을 사용하려면, 반드시 async 함수를 사용해야 한다.

Future<void> checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}

 

 

async 함수는 시간이 많이 걸리는 작업을 기다릴 수 있지만, 그 작업들을 기다리지는 않는다.

대신, async 함수는 첫번째 await 표현식을 만날 때까지만 실행한다.

그리고 Future 객체를 반환하면, await 표현식이 완료된 이후부터 실행을 재개한다.

 

try-catch finally를 통해 await을 사용하는 코드의 에러를 다루고 처리한다.

try {
  version = await lookUpVersion();
} catch (e) {
  // React to inability to look up the version
}

 

async 함수에 await 키워드를 여러 번 사용할 수도 있다.

var entrypoint = await findEntryPoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);

 

await 표현식에서, 표현식의 값은 일반적으로 Future다.

그렇지 않으면, 자동으로 Future로 래핑된다.

Future 객체는, 객체를 반환하겠다는 약속을 나타낸다.

await 표현식의 값은 반환된 객체다.

await 표현식은 객체가 사용 가능해질 때까지 실행을 멈춘다.

 

 

await을 사용할 때 컴파일 타임 에러가 발생한다면, async 함수 내에 await이 있는지 확인하자.

void main() async {
  checkVersion();
  print('In main: version is ${await lookUpVersion()}');
}

 

 

- 비동기 함수 선언

async 함수는 바디가 async 한정자로 표시된 함수다.

 

함수에 async 키워드를 추가하면, Future를 반환한다.

예를 들어, String을 반환하는 동기 함수를 보자.

String lookUpVersion() => '1.0.0';

Future 구현에 시간이 많이 걸리기 때문에 비동기 함수로 변경하면, 반환된 값은 Future다.

Future<String> lookUpVersion() async => '1.0.0';

 

함수 바디는 Future를 사용할 필요가 없다. Dart는 필요한 상황에 Future 객체를 생성한다.

함수가 유용한 값을 반환하지 않는다면, 반환 값을 Future<void>로 설정하자.

 

 

- 스트림 처리

스트림으로부터 값을 얻어야 한다면, 두 가지 선택지가 있다.

async와 비동기 for loop(await for)를 사용하거나, 스트림 API를 사용한다.

 

await for를 사용하기 전에 코드를 더 명확하게 만들고, 스트림의 모든 결과를 정말 기다리고 싶은지 확인하자.

예를 들어, UI 프레임워크는 끝없는 이벤트 스트림을 보내기 때문에, UI 이벤트 리스너에 대해 await for를 사용하면 안된다.

 

비동기 for loop는 다음과 같은 형태를 가진다.

await for (varOrType identifier in expression) {
  // Executes each time the stream emits a value.
}

표현식의 값은 반드시 스트림이어야 한다. 실행은 다음과 같이 진행된다.

1. 스트림이 값을 방출할 때까지 기다린다.

2. 방출된 값으로 변수가 설정되고, for loop 바디가 실행된다.

3. 스트림이 닫힐 때 까지 1번과 2번을 반복한다.

 

스트림 감지를 멈추려면, for 루프에서 벗어나서 스트림의 구독을 취소하는 break과 return 문을 사용할 수 있다.

 

비동기 for loop를 구현할 때 컴파일 타임 에러를 만난다면, async 함수 내에 await for를 사용하고 있는지 확인하자.

void main() async {
  // ...
  await for (final request in requestServer) {
    handleRequest(request);
  }
  // ...
}

 

 

- Generators

값들의 시퀀스를 느리게 생성해야할 때, generator 함수를 고려하자.

Dart는 기본적으로 두 종류의 generator 함수를 지원한다.

1. 동기 generator : Iterable 객체를 반환한다.

2. 비동기 generator : Stream 객체를 반환한다.

 

동기 generator 함수를 구현하기 위해, 함수 바디에 sync*를 표시하고, yield 문을 사용하여 값을 제공한다.

Iterable<int> naturalsTo(int n) sync* {
  int k = 0;
  while (k < n) yield k++;
}

 

비동기 generator 함수를 구현하기 위해, 함수 바디에 async*를 표시하고, yield 문을 사용하여 값을 제공한다.

Stream<int> asynchronousNaturalsTo(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}

 

generator를 재귀로 한다면, yield*를 사용하여 성능을 향상시킬 수 있다.

Iterable<int> naturalsDownFrom(int n) sync* {
  if (n > 0) {
    yield n;
    yield* naturalsDownFrom(n - 1);
  }
}

 

 

- Callable classes

Dart 클래스의 인스턴스가 함수처럼 호출되도록 하려면, call() 메소드를 구현한다.

 

다음 코드에서 WannabeFunction 클래스는, 세 개의 문자열을 가져와서 연결, 공백 구분, 느낌표를 추가하는 call() 함수를 정의한다.

class WannabeFunction {
  String call(String a, String b, String c) => '$a $b $c!';
}

var wf = WannabeFunction();
var out = wf('Hi', 'there,', 'gang');

void main() => print(out);

 

 

- Isolates

대부분의 컴퓨터(모바일 플랫폼에서도)는 멀티 코어 CPU를 가진다.

모든 코어를 활용하기 위해, 개발자는 전통적으로 동시에 실행되는 공유 메모리 스레드를 사용한다.

그러나 공유 상태 동시성은 오류가 발생하기 쉽고, 복잡한 코드로 이어질 수 있다.

 

스레드 대신에, 모든 Dart 코드는 isolate 내부에서 실행된다.

각 Dart isolate는 단일 실행 스레드를 가지며, 다른 isolate와 변경 가능한 객체를 공유하지 않는다.

 

 

- Typedefs

type alias(typedef 키워드로 선언되기 때문에 typedef라고도 함)는 타입을 참조하는 간결한 방법이다.

다음 코드는 IntList라고 명명된 type alias를 사용한다.

typedef IntList = List<int>;
IntList il = [1, 2, 3];

 

type alias는 타입 파라미터를 가질 수 있다.

typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {}; // Verbose.
ListMapper<String> m2 = {}; // Same thing but shorter and clearer.

 

 

대부분의 상황에서 함수에는 typedef 대신, 인라인 함수 타입을 추천한다.

하지만 함수 typedef는 여전히 유용할 수 있다.

typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

void main() {
  assert(sort is Compare<int>); // True!
}

 

 

- Metadata

코드에 추가 정보를 주기 위해, 메타데이터를 사용하자.

메타데이터 애노테이션은 문자 @로 시작하고, 컴파일 타임 상수(deprecated)에 대한 참조 또는 constant 생성자에 대한 호출이 온다.

 

@Deprecated, @deprecated, @override는 모든 Dart 코드에서 사용할 수 있다.

class Television {
  /// Use [turnOn] to turn the power on instead.
  @Deprecated('Use turnOn instead')
  void activate() {
    turnOn();
  }

  /// Turns the TV's power on.
  void turnOn() {...}
  // ···
}

 

자신의 메타데이터 애노테이션을 정의할 수도 있다.

library todo;

class Todo {
  final String who;
  final String what;

  const Todo(this.who, this.what);
}
import 'todo.dart';

@Todo('seth', 'make this do something')
void doSomething() {
  print('do something');
}

 

메타데이터는 라이브러리, 클래스, typedef, 타입 파라미터, 생성자, 팩토리, 함수, 필드, 파라미터, 변수 선언부, import만 export 지시문 앞에 나타날 수 있다.

리플렉션을 이용하여 런타임에 메타데이터를 검색할 수 있다.

 

 

- Comments

void main() {
  // TODO: refactor into an AbstractLlamaGreetingFactory?
  print('Welcome to my Llama farm!');
}

한 줄 주석 : // ~

 

void main() {
  /*
   * This is a lot of work. Consider raising chickens.

  Llama larry = Llama();
  larry.feed();
  larry.exercise();
  larry.clean();
   */
}

여러 줄 주석 : /* ~ */

 

 

- Documentation Comments

문서 주석은 /// 또는 //*로 시작하는, 한 줄 또는 여러 줄 주석이다.

연이은 줄에 ///를 사용하는 것은 여러 줄의 문서 주석과 같은 효과를 가진다.

 

문서 주석 안에서 대괄호로 묶이지 않는 한, 분석기는 모든 텍스트를 무시한다.

대괄호를 사용하여 클래스, 메소드, 필드, 탑레벨 변수, 함수, 파라미터를 참조할 수 있다.

대괄호 내에 이름은, 문서화된 프로그램 요소의 어휘 범위에서 확인된다.

 

다음 코드는, 다른 클래스와 인자를 참조하는 문서 주석을 보여준다.

/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
///
/// Just like any other animal, llamas need to eat,
/// so don't forget to [feed] them some [Food].
class Llama {
  String? name;

  /// Feeds your llama [food].
  ///
  /// The typical llama eats one bale of hay per week.
  void feed(Food food) {
    // ...
  }

  /// Exercises your llama with an [activity] for
  /// [timeLimit] minutes.
  void exercise(Activity activity, int timeLimit) {
    // ...
  }
}

클래스의 생성된 문서에서, [feed]는 feed 메소드 문서에 대한 링크가 되고, [Food]는 Food 클래스 문서에 대한 링크가 된다.

 

Dart 코드를 구문 분석하고 HTML 문서를 만드려면, 다트 문서 제작 툴인 dart doc을 사용할 수 있다.

반응형

'플러터' 카테고리의 다른 글

Flutter - don't support null safety  (0) 2022.06.01
Dart 문법 공부 - 5  (0) 2022.05.30
Dart 문법 공부 - 4  (0) 2022.05.29
Dart 문법 공부 - 3  (0) 2022.05.29
Dart 문법 공부 - 2  (0) 2022.05.28

+ Recent posts