본문 바로가기

Programming/Dart & Flutter

Dart 6일 차 - Language Tour (6/7)

Adding features to a class: mixins

https://dart.dev/guides/language/language-tour#adding-features-to-a-class-mixins

Mixins 는 클래스 코드를 재사용하는 방법이다.

 

사용하려면 with 키워드와 함께 mixin 이름을 지정해준다. 

 

mixins 를 구현하려면 Object 를 상속하는 class 를 만들고 생성자를 구현하지 않는다. (매개변수가 없는 기본 생성자를 사용한다.)

class 키워드 대신 mixin 을 사용한다.

 

특정 타입에 해당하는 mixin 을 지정할 수 있다. 

뒤에 on 키워드와 함께 type 을 써주면 된다.

Class variables and methods

https://dart.dev/guides/language/language-tour#class-variables-and-methods

클래스 변수, 메서드를 만들려면 static 키워드를 사용한다.

Static variables

static 변수는 상태와 상수에 유용하다.

static 변수는 사용되기 전까지 초기화되지 않는다.

Static methods

static 메서드는 인스턴스의 연산이 아닌다. 그래서 this 를 사용할 수 없다.

static 메서드는 컴파일 타임 상수로 사용할 수 있다.

예를 들면 static 메서드를 상수 생성자에 매개변수로 넘길 수 있다.

Generics

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

 

API 문서에서 List type 을 보게 되면 List<E> 와 같은 것을 보실 수 있다.

<...> 은 List 가 제네릭 타입이라는 표시이다.

기본 컨벤션에 따르면 대부분의 타입 변수는 한문자로 사용한다.

Why use generics?

제네릭은 보통 타입 안정성을 요구한다. 그러나 그건 더 많은 이득이 있다.

  • 적절하게 제네릭타입을 지정하면 생성되는 코드가 더 좋을 수 있다. (컴파일 후 최적화 과정 중에서 코드가 더 좋아진다는 의미인 듯)
  • 코드 중복을 줄이기 위해 사용할 수 있다.

만약 list 에 String 만 포함한다면 List<String> 이다. 

실수로 String 이 아닌 값을 넣는 것을 발견할 수 있다. (컴파일 오류)

 

제네릭을 사용하는 다른 이유는 코드 중복을 제거하는 것이다.

정적 분석을 여전히 이용하면서 다양한 타입에 대해서 하나의 인터페이스와 구현을 공유하도록 한다.

Using collection literals

List, set, map literals 는 매개변수화 될 수 있다.

매개변수화된(Parameterized) literals 는 이미 본 것과 같은 형태이다. 

중/대 괄호가 시작하기 전에 <type>, <keyType, valueType> 을 추가하는 것을 제외하는 형태로

Using parameterized types with constructors

생성자를 사용할 때 하나 이상의 타입을 지정하는 경우 클래스명 뒤에 < > 사이에 타입을 지정한다.

Generic collections and the types they contain

Dart 제네릭 타입은 구체적이다. 타입에 대한 정보를 런타입까지 가져간다.

반대로 자바는 런타임 때 제네릭 정보가 제거된다.

Restricting the parameterized type

제네릭 타입을 구현할 때 타입의 제약을 원할 것이다.

이때는 extends 키워드를 이용할 수 있다.

<T extends SomeBaseClass> 

라고 하면 SomeBaseClass 를 상속받은 하위 클래스 중 하나이다 라는 의미이다.

Using generic methods

메서드에서도 제네릭을 사용할 수 있다.

  • 메서드의 return 타입
  • 매개변수 타입
  • 지역 변수 타입 

Libraries and visibility

https://dart.dev/guides/language/language-tour#libraries-and-visibility

 

import, library 키워드는 모듈화 된, 공유 가능한 코드를 만드는데 도움을 준다.

Using libraries

다른 라이브러리의 범위를 지정하여 import 를 사용할 수 있다.

import 의 매개변수는 libraray 를 지정하는 URI 이다.

내장 라이브러는 특별히 dart: scheme 을 가진다.

다른 라이브러리는 파일 시스템의 path 나 package: scheme 을 사용할 수 있다.

package: scheme 은 pub tool 과 같은 패키지 매니저에 의해서 제공되는 라이브러리를 지정한다.

Specifying a library prefix

만약 identifier 가 충돌 나는 두 개의 라이브러리를 import 하려고 한다면 하나 이상의 라이브러리에 대해서 prefix 를 지정할 수 있다.

Importing only part of a library

만약 라이브러리의 특정 부분만 사용하고 싶다면 선택적으로 사용할 수 있다.

import 마지막에 show, hide 키워드를 사용해서 할 수 있다.

Lazily loading a library

https://dart.dev/guides/language/language-tour#asynchrony-support

 

lazy/deferred loading 은 웹앱에서 필요에 의해서 라이브러리를 로드할 수 있도록 허용한다.

  • 웹앱의 초기 시작 시간을 줄일 수 있다.
  • A/B 테스트팅을 할 수 있다.
  • 드물게 필요한 기능을 로드할 때 사용한다.

사용하라면 import 끝에 deferred as 키워드를 사용한다.

만약 해당 라이브러리가 필요해지면 loadLibrary() 함수로 로드할 수 있다.

loadLibrary 는 여러 번 호출되어도 한 번만 로드한다.

 

deffered loading 을 사용할 때 주의해라

  • deferred 라이브러리의 상수는 라이브러리가 로드되기 전까지 사용할 수 없다.
  • import 라이브러리에서 deferred 라이브러리의 type 을 사용할 수 없다. 인터페이스 타입을 import, deffered 라이브러리로 다 옮김는 것을 고려해야 한다... (이 부분은 잘 이해가 안되는데... 아마도 lazy 이다 보니 type 을 바로 쓸 수 없는 이슈인 듯하다. 그래서 interface 를 만들어서 사용하려고 하는 측으로 이동하라고 하는 듯하다.)
  • dart 는 deffered 를 네임스페이스처럼 사용할 수 있도록 하기 위해 암시적으로 loadLibrary 를 네임스페이스에 넣었다.

Asynchrony support

Dart 라이브러리는 Futer, Stream Object 를 리턴하는 함수들이 있다.

이 함수들은 비동기이다. 연산이 끝나길 기다리지 않고 시간이 걸리는 연산을 설정 후 리턴한다.

 

비동기 프로그래밍에는 async await 키워드가 있다. 동기 코드처럼 비동기 코드를 사용할 수 있도록 해준다.

Handling Futures

완료된 Future 의 결과를 원할 때 두 가지 선택이 있다.

  • async, await 를 사용한다.
  • Future API 를 사용한다.

async, await 를 사용한 코드는 비동기이지만 동기 코드와 비슷하다.

await 를 사용하기 위해서는 코드는 async 함수에 있어야 한다. 

await 를 사용하는 코드에서 error, cleanup 을 처리하기 위해 try, catch, finally 를 사용한다.

async 함수 안에서 await 를 여러번 사용할 수 있다.

await 를 사용한 결과는 항상 Future 이다. 만약 그렇지 않다고 해도 Future 에 의해 감싸 진다.

Future 객체는 object 를 리턴할 것이라고 약속한다. 

 

await 를 사용하는데 컴파일 타입 에러가 발생한다면 await 가 async 함수 안에 있는지 확인해라.

Declaring async functions

async 함수는 async 가 표시되어 있는 함수이다.

함수에 async 키워드를 붙이면 Future 를 리턴하게 만든다.

 

함수 안에서 Future API 를 사용할 필요는 없다. 

Dart 는 필요하면 Future 객체를 만든다.

만약 함수가 값을 리턴하지 않는다면 Future<Void> 를 리턴하도록 만든다.

Handling Streams

스트림에서 값을 얻길 원할 때 두 가지 선택이 있다.

  • async, await for 를 사용한다. (종료되는 스트림이어야 하는듯)
  • Stream API 를 사용한다.

await for 은 다음과 같이 처리된다.

  1. 스트림이 값을 emit 하기 전까지 기다린다.
  2. emit 된 값과 함께 loop 의 코드를 실행한다.
  3. 스트림이 종료될 때까지 1, 2를 반복한다.

await for 를 종료하기 위해서는 break, return 을 사용한다.

 

만약 await for 를 사용하는데 컴파일 에러가 발생한다면 await for 가 async 함수 안에 있는지 확인해라.

Generator

dart.dev/guides/language/language-tour#generators

 

연속된 값을 lazy 하게 생산할때 generator 함수 사용을 고려할 수 있다.

dart 는 두가지의 generator 함수를 제공 한다.

  • Synchronous generator, Iterable object 를 리턴한다.
  • Asynchronous generator, Stream object 를 리턴한다.

synchronous generator 함수를 구현하려면 함수에 sync* 를 표시하고 값을 전달하기 위해 yield 를 사용한다.

aysnchronous generator 함수를 구현하려면 함수에 async* 를 표시하고 값을 전달하기 위해 yield 를 사용한다.

 

만약 generator 함수가 재귀이면 yield* 를 사용하여 성능 향상을 할 수 있다.

Callable classes

dart.dev/guides/language/language-tour#callable-classes

 

call() 함수를 구현하여 인스턴스를 함수처럼 호출하는 것을 허용한다.

 

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음

태그