타입

타입스펙 에서 Elixir

1개의 연습 문제

타입스펙 소개

Elixir는 동적으로 타입이 지정되는 언어예요. 따라서 컴파일 시점의 타입 검사를 제공하지 않아요. 그래도 타입 명세는 유용할 수 있는데, 그 이유는 다음과 같아요:

  • 문서 역할을 해요.
  • Dialyzer 같은 정적 분석 도구가 잠재적인 버그를 찾는 데 사용할 수 있어요.

함수 정의 바로 앞에 @spec 모듈 속성을 쓰면 함수에 타입 명세를 추가할 수 있어요.

@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
def longer_than?(string, length), do: String.length(string) > length

타입

타입 명세에 쓸 수 있는 표현식은 다음과 같아요:

  • 기본 타입, 예를 들면:

    • boolean()
    • integer(), non_neg_integer(), pos_integer(), float()
    • list()
    • map()
    • any()
  • 타입의 합집합:

    • 예: integer() | list(integer())
  • 매개변수화된 타입:

    • 예: list(integer()) - 정수의 배열
    • 예: %{age: integer()} - :age 키 아래에 정수 값을 가진 맵
  • 원격 타입(어떤 모듈에 정의된 타입), 예를 들면:

  • 리터럴, 예를 들면:

    • %{} - 빈 맵
    • [] - 빈 배열 (하지만 [any()]는 비어 있지 않은 배열이에요)
    • 예: :ok - 아톰 리터럴
  • 내장 특수 타입, 예를 들면:

    • char() - 0..0x10FFFF 범위의 정수
    • charlist() - 문자(char)의 배열
    • keyword() - 첫 번째 원소가 아톰인, 원소 두 개짜리 튜플의 배열
  • 사용자 정의 타입

모든 타입의 전체 목록은 공식 문서의 "Typespecs" 섹션에서 확인할 수 있어요.

인자 이름 지정

타입 명세의 인자에는 이름을 붙일 수도 있는데, 같은 타입의 인자가 여러 개일 때 구분하는 데 유용해요.

@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()

사용자 정의 타입

사용자 정의 타입은 다음 세 가지 모듈 속성 중 하나로 정의할 수 있어요:

  • @type - 공개 타입을 정의해요
  • @typep - 비공개 타입을 정의해요
  • @opaque - 구조는 비공개인 공개 타입을 정의해요
@type color :: {hue :: integer, saturation :: integer, lightness :: integer}

@spec to_hex(color()) :: String.t()

String.t() vs binary() vs string()

String.t()는 Elixir 문자열에 사용해야 하는 올바른 타입이에요. Elixir 문자열은 UTF-8로 인코딩된 바이너리예요. 엄밀히 말하면 String.t()는 binary()로 정의되어 있고, 분석 도구에게 이 두 타입은 동등해요. 하지만 Elixir 문자열을 다루는 함수를 문서화할 때는 String.t()가 의도를 더 잘 드러내는 선택이에요.

반면에 string()은 다른 타입이에요. Erlang 문자열이고, Elixir에서는 charlist라고 불러요. 타입 명세에서는 string() 타입을 피하고 대신 charlist()를 사용해야 해요.

Dialyzer

Dialyzer는 Erlang과 Elixir 코드에서 타입 오류 같은 문제를 찾아낼 수 있는 정적 분석 도구예요. Elixir 프로젝트에서 Dialyzer를 사용하는 가장 쉬운 방법은 Dialyxir를 쓰는 거예요.

GitHub에서 편집 링크가 새 창이나 탭에서 열려요

타입스펙 배우기