๋ฐ˜์‘ํ˜•

Dart์™€ JavaScript๋Š” ๋งŽ์€ ๊ฐœ๋…์„ ๊ณต์œ ํ•œ๋‹ค. Dart ์—ญ์‹œ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ์‹คํ–‰๋˜๊ณ , ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ Future๋ผ๋Š” ๊ฐœ๋…์ด ์กด์žฌํ•œ๋‹ค. Future๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ Promise์™€ ๋น„์Šทํ•˜๋‹ค. Dart๋Š” ์ •์  ํƒ€์ž… ์–ธ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝํ—˜์ด ์žˆ๋‹ค๋ฉด Dart๋ฅผ ๋” ์‰ฝ๊ฒŒ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋‹ค.

 

Dart์™€ JavaScript์˜ ๋‹ค๋ฅธ ์ ๊ณผ ๋น„์Šทํ•œ ์ ์„ Learning Dart as a JavaScript developer ํŽ˜์ด์ง€์— ์ž์„ธํžˆ ์„ค๋ช…๋ผ ์žˆ์–ด์„œ ์ •๋ฆฌํ•ด๋ดค๋‹ค.

 

๐Ÿ’ก ์•„๋ž˜๋Š” Part 1์—์„œ ์ด์–ด์ง€๋Š” Part 2 ๋‚ด์šฉ.

 

 

Asynchrony


์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Dart ๊ฐ€์ƒ๋จธ์‹ (VM)์€ ๋‹จ์ผ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๋ชจ๋“  ์ฝ”๋“œ๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜์ง€๋งŒ, ๋น„๋™๊ธฐ ๋„๊ตฌ๋ฅผ ํ†ตํ•ด ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Futures

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์— Promise๊ฐ€ ์žˆ๋‹ค๋ฉด Dart์—” Future๊ฐ€ ์žˆ๋‹ค. ์ž‘๋™ ๋ฐฉ์‹ ์—ญ์‹œ ๋น„์Šทํ•˜๋‹ค.

// JS
const httpResponseBody = func();

httpResponseBody.then((value) => {
  console.log(`Promise resolved to a value: ${value}`);
});
// Dart
Future<String> httpResponseBody = func();

httpResponseBody.then((String value) {
  print('Future resolved to a value: $value');
});

 

Futures๋Š” ํ”„๋กœ๋ฏธ์Šค์ฒ˜๋Ÿผ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๊ณ  catchError ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

// JS
httpResponseBody
  .then(...)
  .catch(err => {
    console.log(
      "Promise encountered an error before resolving."
    );
  });
// Dart
httpResponseBody
  .then(...)
  .catchError((err) {
    print(
      'Future encountered an error before resolving.'
    );
  });

 

Promise.resolve() ์ฒ˜๋Ÿผ ์ฆ‰์‹œ ์™„๋ฃŒ๋˜๋Š” Future๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

String str = 'String Value';
Future<String> strFuture = Future<String>.value(str);
strFuture.then(print); // String Value

 

Async/Await

Dart๋„ Async/Await ๊ตฌ๋ฌธ์„ ์ง€์›ํ•˜๋ฉฐ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์ฒ˜๋Ÿผ async ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ํ•จ์ˆ˜๋Š” Future๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด String์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์— async๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋ฉด Future<String>์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

// Promise<string> ๋ฐ˜ํ™˜
async function fetchString() {
  return "String Value";
}

fetchString().then((str) => {
  console.log(str); // String Value
});
// Future<String> ๋ฐ˜ํ™˜
Future<String> fetchString() async {
  return 'String Value';
}

fetchString().then((String str) {
  print(str); // String Value
});

 

then() ๋Œ€์‹  await ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ Future ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ await ํ‚ค์›Œ๋“œ๋Š” async ํ•จ์ˆ˜ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// await๋Š” async ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
Future<void> asyncFunction() async {
  var str = await fetchString();
  print(str); // 'String Value'
}

 

Streams

  • Dart์—์„  rxjs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ œ๊ณตํ•˜๋Š” Observable๊ณผ ์œ ์‚ฌํ•œ ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•œ๋‹ค.
  • ์ŠคํŠธ๋ฆผ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ Future์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ์ด๋ฒคํŠธ ๋ฒ„์Šค(event bus)์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค. ์ŠคํŠธ๋ฆผ์€ ์ˆ˜์‹ ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์™„๋ฃŒ ํ˜น์€ ์‹คํŒจ ์ƒํƒœ์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Listening

์ŠคํŠธ๋ฆผ์ด ๊ฐ’์„ ์ „์†กํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์˜ listen ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

Stream<int> stream = ...
stream.listen((int value) {
  print('A value has been emitted: $value');
});

 

listen ๋ฉ”์„œ๋“œ๋Š” ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ํ˜น์€ ์™„๋ฃŒ๋ฅผ ์œ„ํ•œ ์„ ํƒ์  ์ฝœ๋ฐฑ์„ ํฌํ•จํ•œ๋‹ค.

stream.listen(
  // onData: ์ŠคํŠธ๋ฆผ์ด ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ ํ˜ธ์ถœ
  (int value) {
    // ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง
  },
  // onError: ์ŠคํŠธ๋ฆผ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ
  onError: (err) {
    print('Stream encountered an error! $err');
  },
  // onDone: ์ŠคํŠธ๋ฆผ์ด ์™„๋ฃŒ๋์„ ๋•Œ ํ˜ธ์ถœ
  onDone: () {
    print('Stream completed!');
  },
);

 

listen ๋ฉ”์„œ๋“œ๋Š” StreamSubscription ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด ์ŠคํŠธ๋ฆผ ์ˆ˜์‹ ์„ ์ค‘์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

StreamSubscription subscription = stream.listen(...);
subscription.cancel();

 

๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ(async ํ•จ์ˆ˜) ์•ˆ์—์„œ ์ŠคํŠธ๋ฆผ๊ณผ for-in ๋ฃจํ”„๋ฅผ ๊ฒฐํ•ฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Future<int> sumStream(Stream<int> stream) async {
  var sum = 0;
  await for (final value in stream) {
    sum += value;
  }
  return sum;
}

 

try-catch ๋ฌธ์œผ๋กœ ์ŠคํŠธ๋ฆผ ์ˆ˜์‹  ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

try {
  await for (final value in stream) { ... }
} catch (err) {
  print('Stream encountered an error! $err');
}

 

Creating streams

Stream ํด๋ž˜์Šค๋Š” ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

 

Stream.fromFuture๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Future๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

Stream.fromIterable์„ ์‚ฌ์šฉํ•˜์—ฌ Iterable ์ปฌ๋ ‰์…˜์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

Stream.periodic์„ ์‚ฌ์šฉํ•˜์—ฌ ์ผ์ • ๊ฐ„๊ฒฉ์œผ๋กœ ๊ฐ’์„ ์ „์†กํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

StreamController๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๊ณ , ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

var listeners = 0; // ๋ฆฌ์Šค๋„ˆ ๊ฐœ์ˆ˜๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ณ€์ˆ˜
StreamController<int>? controller; // ์ปจํŠธ๋กค๋Ÿฌ ์„ ์–ธ

controller = StreamController<int>(
  // ์ƒˆ๋กœ์šด ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์ŠคํŠธ๋ฆผ์„ ๊ตฌ๋…ํ•  ๋•Œ๋งˆ๋‹ค ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  onListen: () {
    // listeners ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ํ•ด๋‹น ๊ฐ’์„ ๋ฆฌ์Šค๋„ˆ์—๊ฒŒ ์ „์†ก
    controller!.add(++listeners);
    // 5๋ฒˆ์งธ ๋ฆฌ์Šค๋„ˆ ์ดํ›„์—๋Š” ์ŠคํŠธ๋ฆผ์„ ๋‹ซ์Œ
    if (listeners > 5) controller.close();
  }
);

// ์ŠคํŠธ๋ฆผ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ŠคํŠธ๋ฆผ ๊ฐ€์ ธ์˜ค๊ธฐ
var stream = controller.stream;

// ์ŠคํŠธ๋ฆผ ๊ตฌ๋…
stream.listen((int value) {
  print('$value'); // 1
});

 

ํ•จ์ˆ˜์— sync* ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ๋™๊ธฐ์‹ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๊ฐ€ ๋˜๋ฉฐ ์ด ํ•จ์ˆ˜๋Š” ์ดํ„ฐ๋Ÿฌ๋ธŒ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ํ•จ์ˆ˜์— async* ๋ฅผ ๋ถ™์ด๋ฉด ๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๊ฐ€ ๋˜๊ณ  ์ด ํ•จ์ˆ˜๋Š” ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—์„œ yield๋Š” ์ฃผ์–ด์ง„ ๊ฐ’์„ ์ŠคํŠธ๋ฆผ์— ์ „๋‹ฌํ•œ๋‹ค.

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

Stream<int> stream1 = asyncNaturalsTo(5);
stream1.listen(print); // 0, 1, 2, 3, 4

Stream<int> stream2 = asyncNaturalsTo(5);
// stream์€ forEach ๋ฉ”์„œ๋“œ๋„ ์ œ๊ณตํ•œ๋‹ค
// yield ๋  ๋•Œ๋งˆ๋‹ค forEach์˜ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋œ๋‹ค
stream2.forEach(print); // 0, 1, 2, 3, 4

 

๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์—์„œ yield*๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค๋ฅธ ๋น„๋™๊ธฐ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์˜ ๋ชจ๋“  ๊ฐ’์„ ํ˜„์žฌ ์ŠคํŠธ๋ฆผ์— ์ˆœ์ฐจ์ ์œผ๋กœ yield ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

Classes


Dart์™€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํด๋ž˜์Šค๋Š” ์œ ์‚ฌํ•ด๋ณด์ด์ง€๋งŒ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํด๋ž˜์Šค๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ์‹ธ๋Š” ๋ž˜ํผ(Wrapper)์— ๊ฐ€๊น๋‹ค. ๋ฐ˜๋ฉด, Dart์˜ ํด๋ž˜์Šค๋Š” ์–ธ์–ด์˜ ํ‘œ์ค€ ๊ธฐ๋Šฅ์ด๋‹ค.

 

"this" context

  • Dart์˜ this๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ”์ธ๋”ฉ ํ•  ์ˆ˜ ์—†๊ณ , ์‹คํ–‰ ์ปจํ…์ŠคํŠธ์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • Dart์˜ this๋Š” ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋ฉฐ, ํ•ญ์ƒ ํ˜„์žฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

 

Constructors

Standard constructor

Dart์˜ ํ‘œ์ค€ ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋Š” ์ „์ฒด ํด๋ž˜์Šค ์ด๋ฆ„์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ƒ์„ฑ์ž์˜ ๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜์— ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋• new ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

class Point {
  // ํด๋ž˜์Šค ํ•„๋“œ (์ธ์Šคํ„ด์Šค ์†์„ฑ ์ •์˜)
  final double x;
  final double y;

  // ํ‘œ์ค€ ์ƒ์„ฑ์ž ": this.x = x, this.y = y" ๋ถ€๋ถ„์€ ์ดˆ๊ธฐํ™” ๋ฆฌ์ŠคํŠธ
  Point(double x, double y) : this.x = x, this.y = y;
}

// Point ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
Point p = Point(3, 5);

 

Initializer lists

์ดˆ๊ธฐํ™” ๋ฆฌ์ŠคํŠธ๋Š” ์ƒ์„ฑ์ž๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ๊ฐ’์„ ํด๋ž˜์Šค ํ•„๋“œ์— ํ• ๋‹นํ•˜๋Š” ์ž‘์—…์ด๋‹ค. ์ดˆ๊ธฐํ™” ๋ฆฌ์ŠคํŠธ๋Š” ์ƒ์„ฑ์ž ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋ณธ๋ฌธ ์‚ฌ์ด์— ์‚ฝ์ž…ํ•œ๋‹ค. ์ฝœ๋ก  : ๋’ค์— ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ดˆ๊ธฐํ™”๋ฅผ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๋‹ค. ์ดˆ๊ธฐํ™” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐํ™”๋ฅผ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค(๋ฌธ๋ฒ•์  ์„คํƒ•).

// ์ดˆ๊ธฐํ™” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ
Point(double x, double y): this.x = x, this.y = y {}

// ์ดˆ๊ธฐํ™” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ
Point(this.x, this.y) {...}

 

์ƒ์„ฑ์ž์—์„œ ์œ„์น˜ ์ง€์ • ํ˜น์€ ์ด๋ฆ„ ์ง€์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class Point {
  ...
  // ์„ ํƒ์  ์œ„์น˜ ์ง€์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์„ฑ์ž
  Point(this.x, [this.y = 5]);
  // ์ด๋ฆ„ ์ง€์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์„ฑ์ž
  Point({ required this.y, this.x = 5 });
  // ์œ„์น˜ ์ง€์ •, ์ด๋ฆ„ ์ง€์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋Š” ์ƒ์„ฑ์ž
  Point(int x, int y, { boolean multiply }) {
    ...
  }
  ...
}

 

Named constructors

Dart์—์„  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๋‹ฌ๋ฆฌ ์ƒ์„ฑ์ž๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. Dart์—์„  1๊ฐœ์˜ ์ด๋ฆ„ ์—†๋Š”(unnamed) ์ƒ์„ฑ์ž์™€, ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ด๋ฆ„ ์žˆ๋Š”(named) ์ƒ์„ฑ์ž๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฆ„ ์žˆ๋Š” ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค ์ด๋ฆ„ ๋’ค์— . ์˜จ์ ๊ณผ ์›ํ•˜๋Š” ์ด๋ฆ„์„ ๋ถ™์—ฌ์„œ ์ •์˜ํ•œ๋‹ค.

class Person {
  String name;
  int age;

  // ์ด๋ฆ„ ์—†๋Š” ์ƒ์„ฑ์ž
  Person(this.name, this.age);

  // onlyName ์ด๋ฆ„ ์žˆ๋Š” ์ƒ์„ฑ์ž
  Person.onlyName(this.name, [this.age = 0]);

  // defaultPerson ์ด๋ฆ„ ์žˆ๋Š” ์ƒ์„ฑ์ž
  Person.defaultPerson([this.name = "John", this.age = 30]);
}

void main() {
  final p1 = Person("Zoe", 30);
  final p2 = Person.onlyName("Jane");
  final p3 = Person.defaultPerson();
}

 

Const constructor

์ƒ์„ฑ์ž ์•ž์— const ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” final ์ด์–ด์•ผ ํ•œ๋‹ค. ์ฆ‰, ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•œ ๋ฒˆ ์ดˆ๊ธฐํ™”๋˜๋ฉด ์†์„ฑ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.

class Point {
  final int x;
  final int y;

  const Point(this.x, this.y);
}

void main() {
  Point point = Point(1, 2);
  point.x = 3; // Error! final ๋ณ€์ˆ˜๋Š” ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€
}

 

Constructor redirection

์ƒ์„ฑ์ž ๋งค๊ฐœ๋ณ€์ˆ˜ ๋’ค์— ์ฝœ๋ก (:)๊ณผ this ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ™์€ ํด๋ž˜์Šค์˜ ๋‹ค๋ฅธ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์ƒ์„ฑ์ž ์œ„์ž„(๋˜๋Š” ์ƒ์„ฑ์ž ์ฒด์ด๋‹)์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

class Point {
  double x, y;

  // ๋ฉ”์ธ ์ƒ์„ฑ์ž
  Point(this.x, this.y);

  // ๋ฉ”์ธ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์„œ๋ธŒ ์ƒ์„ฑ์ž
  Point.alongXAxis(double x) : this(x, 0);
}

 

์ƒ์„ฑ์ž ์œ„์ž„์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ์ƒ์„ฑ์ž ๋กœ์ง์„ ๋” ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Factory constructors

ํŒฉํ† ๋ฆฌ ์ƒ์„ฑ์ž๋Š” ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ํ•˜์œ„ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํŠน๋ณ„ํ•œ ์ƒ์„ฑ์ž๋‹ค. ์ผ๋ฐ˜ ์ƒ์„ฑ์ž์™€ ๋‹ฌ๋ฆฌ ํ•ญ์ƒ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค(์ธ์Šคํ„ด์Šค ์žฌ์‚ฌ์šฉ).

class Color {
  final String name;
  final int code;

  // ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๊ณต๊ฐœ(private) ์ƒ์„ฑ์ž
  Color._internal(this.name, this.code);

  // ๋ฏธ๋ฆฌ ์ •์˜๋œ ์ƒ‰์ƒ๋“ค์„ ์ €์žฅํ•˜๋Š” ์ •์ (static) ๋งต
  static final Map<String, Color> _cache = {
    'red': Color._internal('red', 0xFF0000),
    'green': Color._internal('green', 0x00FF00),
    'blue': Color._internal('blue', 0x0000FF),
  };

  // ํŒฉํ† ๋ฆฌ(factory) ์ƒ์„ฑ์ž
  factory Color(String name) {
    // ์บ์‹œ์— ์žˆ์œผ๋ฉด ํ•ด๋‹น ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด ๊ธฐ๋ณธ ์ƒ‰์ƒ(๊ฒ€์ •)์œผ๋กœ ์ƒˆ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    return _cache[name] ?? Color._internal(name, 0x000000);
  }
}

void main() {
  var red1 = Color('red');
  var red2 = Color('red');
  var custom = Color('custom');
 
  print(identical(red1, red2)); // true (๊ฐ™์€ ์ธ์Šคํ„ด์Šค)
  print(red1.code); // 16711680 (0xFF0000)
  print(custom.code); // 0 (0x000000)
}

 

์บ์‹ฑ, ์‹ฑ๊ธ€ํ†ค, ์กฐ๊ฑด๋ถ€ ๊ฐ์ฒด ์ƒ์„ฑ ๋“ฑ ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์—์„œ ํŒฉํ† ๋ฆฌ ์ƒ์„ฑ์ž๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Methods

Dart, JavaScript์—์„œ ๋ฉ”์„œ๋“œ๋Š” ๊ฐ์ฒด์— ๋™์ž‘์„ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜๋‹ค.

class Example {
  // ๋ฉ”์„œ๋“œ
  doSomething() {
    // ...๊ตฌํ˜„
  }
}
class Example {
  // ๋ฉ”์„œ๋“œ
  void doSomething() {
    // ...๊ตฌํ˜„
  }
}

 

Extending classes

Dart์—์„  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜(์˜ค๋ฒ„๋ผ์ด๋“œ) ํ•  ๋• @override ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค.

class Animal {
  int eyes;

  Animal(this.eyes);

  makeNoise() {
    print('???');
  }
}

class Cat extends Animal {
  // ๋ถ€๋ชจ ํด๋ž˜์Šค ์ƒ์„ฑ์ž์— 2๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ํ˜ธ์ถœ (์ƒ์„ฑ์ž ์œ„์ž„)
  Cat() : super(2);

  // makeNoise ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋“œ
  @override
  makeNoise() {
    print('Meow');
  }
}

void main() {
  final cat = Cat();
  print(cat.eyes); // 2
  cat.makeNoise(); // Meow
}

 

๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ–ˆ์–ด๋„ super ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์œ„ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

class Cat extends Animal {
  // ๋ถ€๋ชจ ํด๋ž˜์Šค ์ƒ์„ฑ์ž์— 2๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ํ˜ธ์ถœ (์ƒ์„ฑ์ž ์œ„์ž„)
  Cat() : super(2);

  // makeNoise ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋“œ
  @override
  makeNoise() {
    print('Meow');
    super.makeNoise();
  }
}

void main() {
  final cat = Cat();
  cat.makeNoise(); // Meow, ???
}

 

Classes as interfaces

Dart์—์„  ๋ณ„๋„์˜ interface ํ‚ค์›Œ๋“œ๊ฐ€ ์—†๊ณ , ํด๋ž˜์Šค ์ •์˜ ์ž์ฒด๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•  ๋• implements ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด ํด๋ž˜์Šค B๊ฐ€ implements A๋ฅผ ์„ ์–ธํ•˜๋ฉด, ํด๋ž˜์Šค B๋Š” ํด๋ž˜์Šค A์˜ ๋ชจ๋“  ๊ณต๊ฐœ(public) ๋ฉ”์„œ๋“œ์™€ ์†์„ฑ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. extends ํ™•์žฅ๊ณผ ๋‹ฌ๋ฆฌ ๋ฉ”์„œ๋“œ์™€ ํ•„๋“œ ๊ตฌํ˜„์€ ์ƒˆ ํด๋ž˜์Šค์— ๊ณต์œ ๋˜์ง€ ์•Š๋Š”๋‹ค.

class Consumer {
  consume() {
    print('Eating food...');
  }
}

class Cat implements Consumer {
  @override
  consume() {
    print('Eating mice...');
  }
}

void main() {
  Consumer consumer = Cat();
  consumer.consume(); // Eating mice...
}

 

์ธํ„ฐํŽ˜์ด์Šค๋กœ ์‚ฌ์šฉ๋˜๋Š” ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋Š” ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํด๋ž˜์Šค์— ์ƒ์†๋˜์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ super ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค.

class Cat implements Consumer {
  @override
  consume() {
    print('Eating mice...');
    super.consume(); 
    // Invalid. The superclass `Object` has no `consume` method.
  }
}

 

์—ฌ๋Ÿฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋™์‹œ์— ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋ฅผ ๋‹ค์ค‘ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

class MyClass implements Interface1, Interface2, Interface3 {
  // ์—ฌ๋Ÿฌ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ์™€ ์†์„ฑ ๋ชจ๋‘ ๊ตฌํ˜„
}

 

Abstract classes and methods

ํด๋ž˜์Šค์˜ ํ™•์žฅ(์ƒ์†), ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ abstract๋กœ ํ‘œ๊ธฐํ•œ๋‹ค. ์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ(๊ตฌํ˜„์ด ์—†๋Š” ๋ฉ”์„œ๋“œ)๋ฅผ ํฌํ•จํ•˜๊ณ , ์ด ๋ฉ”์„œ๋“œ๋“ค์€ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„๋ผ์•ผ ํ•œ๋‹ค. ๋ฉ”์„œ๋“œ ๋ณธ๋ฌธ ์—†์ด ์„ ์–ธ๋งŒ ์žˆ๋‹ค๋ฉด ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค.

abstract class Consumer {
  consume();
}

// ์ „์ฒด ํด๋ž˜์Šค ํ™•์žฅ
class Dog extends Consumer {
  consume() {
    print('Eating cookies...');
  }
}

// ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ๊ตฌํ˜„
class Cat implements Consumer {
  consume() {
    print('Eating mice...');
  }
}

 

์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ๋„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค.

abstract class Shape {
  // ์ถ”์ƒ ๋ฉ”์„œ๋“œ
  double area();

  // ์ผ๋ฐ˜ ๋ฉ”์„œ๋“œ
  void printName() {
    print("This is a shape");
  }
}

class Circle extends Shape {
  double radius;

  Circle(this.radius);

  @override
  double area() {
    return 3.14 * radius * radius;
  }
}

void main() {
  var circle = Circle(5);
  circle.printName(); // This is a shape
}

 

Mixins

๋ฏน์Šค์ธ์€ ํด๋ž˜์Šค ๊ฐ„์— ๊ธฐ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋…์œผ๋กœ, ํŠน์ • ํด๋ž˜์Šค์˜ ์ผ๋ถ€์ธ ๊ฒƒ์ฒ˜๋Ÿผ ํ•„๋“œ์™€ ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ•œ ํด๋ž˜์Šค์—์„œ ์—ฌ๋Ÿฌ ๋ฏน์Šค์ธ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ฏน์Šค์ธ์€ ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜๊ฑฐ๋‚˜ ๊ณตํ†ต ์กฐ์ƒ์„ ๊ณต์œ ํ•˜์ง€ ์•Š๋”๋ผ๋„ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์—์„œ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค. Dart์—์„œ ๋ฏน์Šค์ธ์€ with ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ์šฉํ•œ๋‹ค. ์—ฌ๋Ÿฌ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋‚˜์—ดํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—” Dart์˜ with ๊ฐ™์€ ํ‚ค์›Œ๋“œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— Object.assign์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด ๊ฐ์ฒด์— ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ์†์„ฑ์„ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

// Animal ํด๋ž˜์Šค ์ •์˜
class Animal {}

// ๊ธฐ๋Šฅ(Mixins) ์ •์˜
class Flyer {
  fly = () => console.log("Flaps wings");
}
class Walker {
  walk = () => console.log("Walks on legs");
}

// Animal ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค ์ •์˜
class Bat extends Animal {}
class Goose extends Animal {}
class Dog extends Animal {}

// ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์— ์˜ฌ๋ฐ”๋ฅธ ๊ธฐ๋Šฅ์„ ํ˜ผํ•ฉํ•˜์—ฌ ์ƒ์„ฑ
const bat = Object.assign(
  new Bat(), // Bat ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ 
  new Flyer() // Flyer ๊ธฐ๋Šฅ ํ˜ผํ•ฉ
);

const goose = Object.assign(
  new Goose(), // Goose ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ 
  new Flyer(), // Flyer ๊ธฐ๋Šฅ ํ˜ผํ•ฉ
  new Walker() // Walker ๊ธฐ๋Šฅ ํ˜ผํ•ฉ
);

const dog = Object.assign(
  new Dog(), // Dog ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ 
  new Walker() // Walker ๊ธฐ๋Šฅ ํ˜ผํ•ฉ
);

// ์˜ฌ๋ฐ”๋ฅธ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
bat.fly(); 
goose.fly(); 
goose.walk();
dog.walk(); 

// ์ž˜๋ชป๋œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
bat.walk(); // bat ์ธ์Šคํ„ด์Šค์—๋Š” walk ๋ฉ”์„œ๋“œ ์—†์Œ
dog.fly();  // dog ์ธ์Šคํ„ด์Šค์—๋Š” fly ๋ฉ”์„œ๋“œ ์—†์Œ
// Animal ์ถ”์ƒ ํด๋ž˜์Šค ์ •์˜
abstract class Animal {}

// ๊ธฐ๋Šฅ(Mixins) ์ •์˜
class Flyer {
  fly() => print('Flaps wings');
}

class Walker {
  walk() => print('Walks on legs');
}

// Bat ํด๋ž˜์Šค ์ •์˜ - Flyer ๋ฏน์Šค์ธ ์‚ฌ์šฉ
class Bat extends Animal with Flyer {}

// Goose ํด๋ž˜์Šค ์ •์˜ - Flyer์™€ Walker ๋ฏน์Šค์ธ ๋ชจ๋‘ ์‚ฌ์šฉ
class Goose extends Animal with Flyer, Walker {}

// Dog ํด๋ž˜์Šค ์ •์˜ - Walker ๋ฏน์Šค์ธ ์‚ฌ์šฉ
class Dog extends Animal with Walker {}

void main() {
  // ์˜ฌ๋ฐ”๋ฅธ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  Bat().fly();
  Goose().fly();
  Goose().walk();
  Dog().walk();

  // ์ž˜๋ชป๋œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  Bat().walk(); // Walker ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์„œ walk ๋ฉ”์„œ๋“œ ์—†์Œ
  Dog().fly();  // Flyer ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์„œ fly ๋ฉ”์„œ๋“œ ์—†์Œ
}

 

๋ฏน์Šค์ธ์ด ์ผ๋ฐ˜ ํด๋ž˜์Šค๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด class ๋Œ€์‹  mixin ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. mixin ํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.

mixin Walker {
  walk() => print('Walks legs');
}

// Walker๋Š” ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์† ๋ถˆ๊ฐ€
class Bat extends Walker {}

 

์—ฌ๋Ÿฌ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋กœ ๊ฒน์น˜๋Š” ๋ฉ”์„œ๋“œ๋‚˜ ํ•„๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์ด๋• โถ์ž์ฒด ํด๋ž˜์Šค, โท๋ฏน์Šค์ธ(์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ) โธ๋ถ€๋ชจ ํด๋ž˜์Šค ์ˆœ์„œ๋กœ ๊ตฌํ˜„์„ ํƒ์ƒ‰ํ•œ๋‹ค.

abstract class Animal {}

mixin Consumer {
  eat() => print('Consumer Eating...');
}

mixin Flyer {
  eat() => print('Flyer Eating...');

  fly() => print('Flying...');
}

// Bird(์ž์ฒด ํด๋ž˜์Šค) -> (Flyer -> Consumer) -> Animal(๋ถ€๋ชจ ํด๋ž˜์Šค) ์ˆœ์„œ๋กœ ๊ฒ€์‚ฌ
class Bird extends Animal with Consumer, Flyer {
  chirp() => print('Chirping...');
}

void main() {
  Bird bird = Bird();
  bird.eat(); // Flyer Eating...
  bird.chirp(); // Chirping...
  bird.fly(); // Flying...
}

 

Extension

ํ™•์žฅ ๋ฉ”์„œ๋“œ๋Š” ๊ธฐ์กด ํด๋ž˜์Šค๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค์— ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค์˜ ์›๋ž˜ ๊ตฌํ˜„์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ ๋„ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, Dart SDK ๋“ฑ์˜ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ธ๋‹ค.

// ํ™•์žฅ ์ด๋ฆ„(NumberParsing)์€ ์ž„์˜๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
extension NumberParsing on String {
  // String ํƒ€์ž…์— parseInt ํ™•์žฅ ๋ฉ”์„œ๋“œ ์ •์˜
  int parseInt() {
    // ์—ฌ๊ธฐ์„œ this๋Š” ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ String ๊ฐ’
    return int.parse(this);
  }
}

void main() {
  print('123'.parseInt()); // 123
}

 

ํ™•์žฅ ๋ฉ”์„œ๋“œ๋Š” ์ •์  ํƒ€์ž…์— ์˜์กดํ•œ๋‹ค. dynamic ํƒ€์ž… ๋ณ€์ˆ˜์—์„  ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

// ...ํ™•์žฅ ๋ฉ”์„œ๋“œ ์ƒ๋žต

void main() {
  dynamic num = '2';
  print(num.parseInt()); // NoSuchMethodError ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜
}

 

ํ™•์žฅ ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹ค๋ฅธ ํŒŒ์ผ์— ์ •์˜๋˜์–ด ์žˆ๋‹ค๋ฉด ํ˜„์žฌ ํŒŒ์ผ์—์„œ import ํ•ด์•ผ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// ํ™•์žฅ ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๋Š” ํŒŒ์ผ import
import 'string_apis.dart';
// ํ™•์žฅ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ
var age = '42'.parseInt();

 

Getters and setters

Dart์˜ Getter/Setter๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค.

// JavaScript
class Person {
  _age = 0;

  get age() {
    return this._age;
  }

  set age(value) {
    if (value < 0) {
      throw new Error("Age cannot be negative.");
    }
    this._age = value;
  }
}

var person = new Person();
person.age = 10;
console.log(person.age); // 10
// Dart
class Person {
  // ์–ธ๋”์Šค์ฝ”์–ด(_)๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ด๋ฆ„์€ private ํ•„๋“œ๊ฐ€ ๋จ
  // private ํ•„๋“œ๋Š” ์„ ์–ธ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(ํŒŒ์ผ) ์™ธ๋ถ€์—์„  ์ ‘๊ทผ ๋ถˆ๊ฐ€
  int _age = 0;

	// (ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ƒ๋žตํ•œ ์ถ•์•ฝํ˜•) int get age => _age;
  int get age {
    return _age;
  }

  set age(int value) {
    if (value < 0) {
      throw ArgumentError('Age cannot be negative.');
    }
    _age = value;
  }
}

void main() {
  Person person = Person();
  person.age = 10;
  print(person.age); // 10
}

 

์ฐธ๊ณ ๋กœ Dart์—์„œ ํด๋ž˜์Šค ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ๋• this๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Public and private members

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ Dart ๋ชจ๋‘ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ์œ„ํ•œ ํ‚ค์›Œ๋“œ(public, private, protected ๋“ฑ)๊ฐ€ ์—†๋‹ค. ๋ชจ๋“  ํด๋ž˜์Šค ๋ฉค๋ฒ„๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ public ์ด๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ private ๋ฉค๋ฒ„ ์ •์˜๋Š” ํ•ด์‹œ(#)๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , Dart์—์„  ์–ธ๋”์Šค์ฝ”์–ด(_)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

// JavaScript
class Animal {
  eyes; // Public field
  #paws; // Private field

  // Private method
  #printEyes() {
    print(this.eyes);
  }

  // Public method
  printPaws() {
    print(this.#paws);
  }
}
// Dart
class Animal {
  int eyes; // Public field
  int _paws; // Private field

  // Private method
  void _printEyes() {
    print(this.eyes);
  }

  // Public method
  void printPaws() {
    print(this._paws);
  }
}

 

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ private ํ•„๋“œ๋Š” ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ณ , Dart์˜ private ํ•„๋“œ๋Š” ํŒŒ์ผ ์Šค์ฝ”ํ”„ ๊ธฐ๋ฐ˜์œผ๋กœ, ๋‹ค๋ฅธ ํŒŒ์ผ(๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ ‘๊ทผ ๋ฒ”์œ„๋ฅผ ์—ฌ๋Ÿฌ ํŒŒ์ผ๋กœ ํ™•์žฅํ•˜๋ ค๋ฉด part ์ง€์‹œ๋ฌธ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

Late variables

ํด๋ž˜์Šค ํ•„๋“œ๋ฅผ ๋‚˜์ค‘์— ์ดˆ๊ธฐํ™” ํ•ด์•ผํ•  ๋•Œ late ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•„๋“œ๋ฅผ ์„ ์–ธํ•  ๋•Œ ๊ฐ’์„ ์ฆ‰์‹œ ํ• ๋‹นํ•˜์ง€ ์•Š๊ณ  ํ•„์š”ํ•œ ์‹œ์ ์— ์ดˆ๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. late ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ํ•„๋“œ๋Š” non-nullable์ด ๋œ๋‹ค. ์ฆ‰, ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ณ , ์ดˆ๊ธฐํ™” ํ›„์—๋Š” null์ด ๋  ์ˆ˜ ์—†๋‹ค.

 

nullable ํ•„๋“œ๋Š” null ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์•„๋„ null๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐ˜๋ฉด, late ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ non-nullable ํ‚ค์›Œ๋“œ๋Š” null์ด ๋  ์ˆ˜์—†๊ณ  ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ์ ‘๊ทผํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

class Example {
  late String name; // late ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚˜์ค‘์— ์ดˆ๊ธฐํ™”

  void initializeName(String newName) {
    name = newName; // ํ•„์š”ํ•  ๋•Œ ์ดˆ๊ธฐํ™”
  }
}

void main() {
  var example = Example();
  example.initializeName('Dart'); // name ์ดˆ๊ธฐํ™”
  print(example.name); // Dart
}

 

์•„๋ž˜์ฒ˜๋Ÿผ ์ˆœํ™˜ ์ฐธ์กฐ๋กœ ์ดˆ๊ธฐํ™”๋ฅผ ๋Šฆ์ถฐ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— late ํ‚ค์›Œ๋“œ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class PetOwner {
  final String name; // ์ฃผ์ธ ์ด๋ฆ„ (์ˆ˜์ • ๋ถˆ๊ฐ€)
  late final Pet _pet; // ๋‚˜์ค‘์— ์ดˆ๊ธฐํ™”๋˜๋Š” pet ๊ฐ์ฒด

  // Pet ๊ฐ์ฒด๋Š” PetOwner ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์—
  // PetOwner ๊ฐ์ฒด๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•œ ๋‹ค์Œ Pet ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐํ™” ํ•ด์•ผํ•จ
  PetOwner(this.name, String petName) {
    _pet = Pet(petName, this);
  }

  // Pet ๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ Getter
  Pet get pet => _pet;
}

class Pet {
  final String name; // Pet ์ด๋ฆ„
  final PetOwner owner; // Pet ์ฃผ์ธ

  // ์ƒ์„ฑ์ž์—์„œ PetOwner๋ฅผ ๋ฐ›์•„ ์ดˆ๊ธฐํ™”
  Pet(this.name, this.owner);
}

void main() {
  PetOwner owner = PetOwner('Bob', 'Fluffy');
  print(owner.pet.name); // Fluffy
}

 

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ณ€์ˆ˜์˜ ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์—์„  ์ง€์—ญ ๋ณ€์ˆ˜์— late ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Dart์—์„  ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ณ€์ˆ˜๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๋Š” ์ƒํ™ฉ์—์„  ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋•Œ late ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ€์ˆ˜๋ฅผ ๋‚˜์ค‘์— ์ดˆ๊ธฐํ™”ํ•˜๊ฒ ๋‹ค๊ณ  ๋ช…์‹œํ•จ์œผ๋กœ์จ ์ดˆ๊ธฐํ™” ์ฒดํฌ๋ฅผ ๋Ÿฐํƒ€์ž„๊นŒ์ง€ ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ์—์„œ capture ์ธ์ž์˜ true ์—ฌ๋ถ€๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์—” ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, captures ๋ณ€์ˆ˜๋ฅผ late๋กœ ์„ ์–ธํ•˜์—ฌ ๋Ÿฐํƒ€์ž„์—์„œ๋งŒ ์ดˆ๊ธฐํ™” ์ฒดํฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ํ•œ๋‹ค.

doSomething(int n, bool capture) {
  late List<Foo> captures;
  if (capture) captures = [];
  for (var i = 0; i < n; i++) {
    var foo = something(i);
    if (capture) captures.add(foo);
  }
}

 

 

Generics


์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ œ๋„ค๋ฆญ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์ง€๋งŒ, Dart๋Š” ํƒ€์ž… ์•ˆ์ •์„ฑ์„ ๊ฐœ์„ ํ•˜๊ณ  ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ์ œ๋„ค๋ฆญ์„ ์ œ๊ณตํ•œ๋‹ค(ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์˜ ์ œ๋„ค๋ฆญ๊ณผ ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ ์ˆ˜ํ–‰).

 

Generic methods

์ œ๋„ค๋ฆญ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ •์˜ํ•˜๋ ค๋ฉด ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๋’ค์— <T> ํ˜•ํƒœ๋กœ ๋ช…์‹œํ•œ๋‹ค. ์ •์˜ํ•œ ์ œ๋„ค๋ฆญ ํƒ€์ž…์€ ๋ฉ”์„œ๋“œ์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด๋‚˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// Key/Value ๋ชจ๋‘ Object? ํƒ€์ž…์„ ๊ฐ€์ง€๋Š” Map
Map<Object?, Object?> _cache = {};

// ๋ฐ˜ํ™˜ ํƒ€์ž…, ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ชจ๋‘ T ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๊ฐ€์ง€๋Š” ํ•จ์ˆ˜
// ๊ฐ€์žฅ ์•ž ๋ถ€๋ถ„์€ ๋ฐ˜ํ™˜ ํƒ€์ž…
T cache<T>(T value) => (_cache[value] ??= value) as T;

 

์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

// ๋‹ค์ค‘ ์ œ๋„ค๋ฆญ ์ •์˜
T transform<T, Q>(T param1, Q param2) { ... }

// ๋ช…์‹œ์ ์œผ๋กœ ์ •์˜๋œ ํƒ€์ž…์œผ๋กœ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
transform<int, String>(5, 'string value');

// ํƒ€์ž…์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์„ ๋• ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค
transform(5, 'string value');

 

Generic classes

์ œ๋„ค๋ฆญ์„ ํด๋ž˜์Šค์— ์ ์šฉํ•˜์—ฌ ํŠน์ • ํƒ€์ž…์— ๋งž์ถ˜ ํด๋ž˜์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class Cache<T> {
  final Map<String, T> _cache = {};

  // _cache[key] ๊ฐ’์ด ์—†์„์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— T๋Š” nullable ์ด์–ด์•ผ ํ•œ๋‹ค.
  T? getByKey(String key) => _cache[key];

  void setByKey(String key, T value) => _cache[key] = value;
}

void main() {
  final stringCache = Cache<String>();
  stringCache.setByKey('Foo', 'Bar'); // string value๋Š” ์ œ๋„ค๋ฆญ๊ณผ ๋งค์นญ๋˜๋ฏ€๋กœ Valid
  // stringCache.setByKey('Baz', 5); // int ํƒ€์ž…๊ณผ ์ œ๋„ค๋ฆญ์ด ๋งค์นญ๋˜์ง€ ์•Š์•„์„œ Invalid (์ฃผ์„ ์ฒ˜๋ฆฌ)
}

 

๋งŒ์•ฝ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด ๋Ÿฐํƒ€์ž„ ํƒ€์ž…์ด Cache<dynamic>์ด ๋˜๊ณ , setByKey ๋ฉ”์„œ๋“œ์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ž(T)๋Š” ๋ชจ๋“  ํƒ€์ž…์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

Restricting generics

์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•  ๋•Œ extends ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ํƒ€์ž…์œผ๋กœ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด T extends num์€ T๊ฐ€ num ํƒ€์ž…์ด๊ฑฐ๋‚˜ num์˜ ์„œ๋ธŒํƒ€์ž…์ด์–ด์•ผ ํ•œ๋‹ค.

class NumberManager<T extends num> {}

void main() {
  // int, double๋Š” ๋ชจ๋‘ num์ด ์„œ๋ธŒํƒ€์ž…์ด๋ฏ€๋กœ OK
  var managerInt = NumberManager<int>();
  var managerDouble = NumberManager<double>();
  // var managerString = NumberManager<String>(); // Invalid (์ฃผ์„ ์ฒ˜๋ฆฌ)
}

 

Generics in literals

Map, Set, List ๋ฆฌํ„ฐ๋Ÿด์€ ํƒ€์ž… ์ธ์ž(arguments)๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. Dart๊ฐ€ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ์ž˜๋ชป ์ถ”๋ก ํ•  ๋•Œ ์ด ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// ์ž๋™ ํƒ€์ž… ์ถ”๋ก 
var objList = [5, 2.0]; // List<num>
// ๋ช…์‹œ์  ํƒ€์ž… ์ •์˜
var objList = <Object>[5, 2.0]; // List<Object>
// ๋ช…์‹œ์  ํƒ€์ž… ์ •์˜
var objSet = <Object>{5, 2.0}; // Set<Object>

 

Map ๋ฆฌํ„ฐ๋Ÿด์—์„  ํ‚ค์™€ ๊ฐ’์— ๋Œ€ํ•œ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

// ์ž๋™ ํƒ€์ž… ์ถ”๋ก 
var map = {'foo': 'bar'}; // Type: Map<String, String>
// ๋ช…์‹œ์  ํƒ€์ž… ์ •์˜
var map = <String, Object>{'foo': 'bar'}; // Type: Map<String, Object>

 

 

Doc comments


์‹ฑ๊ธ€ ๋ผ์ธ ์ฃผ์„ : // ...

// ์›์˜ ๋„“์ด ๊ณ„์‚ฐ
double area = 3.14 * 4 * 4;

 

๋ฉ€ํ‹ฐ ๋ผ์ธ ์ฃผ์„ : /* ... */

/*
 * ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์š”์†Œ ์ถœ๋ ฅ
 * ๋ฆฌ์ŠคํŠธ๋Š” 1, 2, 3์œผ๋กœ ๊ตฌ์„ฑ
 */
var lst = [1, 2, 3];

 

๋ฌธ์„œํ™” ์ฃผ์„ : /// ... ๋˜๋Š” /** ... */

/// ์ฃผ์–ด์ง„ ์ˆซ์ž๊ฐ€ ์ง์ˆ˜์ธ์ง€ ์—ฌ๋ถ€ ํ™•์ธ
bool isEven(int number) {
  return number % 2 == 0;
}

 

๋ฌธ์„œํ™” ์ฃผ์„์€ dart doc ๋„๊ตฌ๋ฅผ ํ†ตํ•ด ๋ฌธ์„œํ™” ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ API ๋ฌธ์„œํ™”๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. /// ์ฃผ์„์„ ์—ฌ๋Ÿฌ ์ค„์— ๊ฑธ์ณ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ€ํ‹ฐ ๋ผ์ธ ์ฃผ์„๊ณผ ๋™์ผํ•œ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. /// ์Šคํƒ€์ผ์˜ ์ฃผ์„์ด ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฝ๊ธฐ ๋•Œ๋ฌธ์— Dart ํŒ€์—์„œ ๋” ์„ ํ˜ธํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

 


๊ธ€ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋…ธ์…˜ ํŽ˜์ด์ง€์— ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”

 

๋ฐ˜์‘ํ˜•