[elixir] 키워드 목록의 이점은 무엇입니까?

엘릭서에는지도가 있습니다 :

> map = %{:a => "one", :b => "two"} # = %{a: "one", b: "two"}
> map.a                             # = "one"
> map[:a]                           # = "one"

우리는 또한 키워드 목록이 있습니다 :

> kl = [a: "one", b: "two"]       # = [a: "one", b: "two"]
> kl2 = [{:a, "one"},{:b, "two"}] # = [a: "one", b: "two"]
> kl == kl2                       # = true
> kl[:a]                          # = "one"
> kl.a                            # = ** (ArgumentError)

왜 둘 다?

통사론? 키워드 목록은 함수 호출의 마지막 매개 변수로 중괄호 없이도 정의 할 수 있도록 더 유연한 구문을 가지고 있기 때문입니까? 그렇다면지도에이 구문 설탕을주지 않겠습니까?

중복 키? 키워드 목록에 중복 키가있을 수 있기 때문입니까? 지도 스타일 액세스와 중복 키를 모두 원하는 이유는 무엇입니까?

공연? 키워드 목록의 실적이 더 좋기 때문입니까? 그렇다면 왜지도가 있습니까? 그리고 맵은 튜플 목록보다 키로 멤버를 찾는 데 더 효과적이지 않아야합니까?

JS Array와 Ruby Hash 같은 모습? 그게 다야?

나는 구조적으로 서로 다른 데이터 표현임을 이해합니다. 나에게 elixir의 키워드 목록은 예외적 인 구문 (3 개의 다른 구문 변형), 사용 사례가지도와 겹치고 불분명 한 이점을 통해 언어를 복잡하게 만드는 역할을하는 것 같습니다.

키워드 목록을 사용하면 어떤 이점이 있습니까?



답변

                   ┌──────────────┬────────────┬───────────────────────┐
                   │ Keyword List │ Map/Struct │ HashDict (deprecated) │
┌──────────────────┼──────────────┼────────────┼───────────────────────┤
│ Duplicate keys   │ yes          │ no         │ no                    │
│ Ordered          │ yes          │ no         │ no                    │
│ Pattern matching │ yes          │ yes        │ no                    │
│ Performance¹     │ —            │ —          │ —                     │
│ ├ Insert         │ very fast²   │ fast³      │ fast⁴                 │
│ └ Access         │ slow⁵        │ fast³      │ fast⁴                 │
└──────────────────┴──────────────┴────────────┴───────────────────────┘

키워드 목록은 가볍고 그 아래에 간단한 구조가있어 매우 유연합니다. Erlang 규칙 위에 구문 설탕으로 생각할 수 있으므로 너무 추한 코드를 작성하지 않고도 Erlang과 쉽게 인터페이스 할 수 있습니다. 예를 들어 키워드 목록은 Erlang에서 상속 된 속성 인 함수 인수를 나타내는 데 사용됩니다. 경우에 따라 키워드 목록은 유일한 선택이며, 특히 중복 키나 순서가 필요한 경우에는 더욱 그렇습니다. 그들은 단순히 다른 대안과 다른 속성을 가지므로 어떤 상황에는 더 적합하고 다른 상황에는 덜 적합합니다.

맵 (및 Structs)은 해시 기반 구현이 있으므로 실제 페이로드 데이터를 저장하는 데 사용됩니다. 내부적으로 키워드 목록은 각 작업에 대해 순회해야하는 목록 일 뿐이므로 일정한 시간 액세스와 같은 고전적인 키-값 데이터 구조의 속성이 없습니다.

Elixir는 또한 작성 당시 맵의 성능 저하에HashDict 대한 해결 방법으로 도입 되었습니다 . 그러나이 문제는 현재 Elixir 1.0.5 / Erlang 18.0 에서 수정되었으며 향후 버전에서는 더 이상 사용되지 않습니다 .HashDict

Erlang 표준 라이브러리를 자세히 살펴보면 키 / 값 쌍을 저장하는 더 많은 데이터 구조가 있습니다.

  • proplists – Elixir 키워드 목록과 유사
  • – Elixir 맵과 동일
  • dict – Erlang 프리미티브에서 빌드 된 키-값 사전
  • gb_trees – 일반 균형 트리

여러 프로세스 및 / 또는 VM에 키 / 값 쌍을 저장해야하는 경우에도 다음 옵션이 있습니다.

  • ets / dets – (디스크 기반) Erlang 용어 저장소
  • 기억 상실 – 분산 데이터베이스

¹ 일반적으로 말하지만 물론 다릅니다 ™.

² 가장 좋은 경우는 목록 앞에 추가하는 것입니다.

³ Elixir 1.0.5 이상에 적용되며 이전 버전에서는 속도가 느려질 수 있습니다.

HashDict은 이제 지원이 중단됩니다.

⁵ 평균적으로 요소의 절반을 스캔하는 선형 검색이 필요합니다.


답변

키워드 목록의 주요 이점은 기존 elixir 및 erlang 코드베이스와의 하위 호환성입니다.

또한 루비 구문과 유사한 함수 인수로 사용되는 경우 구문 설탕을 추가합니다.

def some_fun(arg, opts \\ []), do: ...
some_fun arg, opt1: 1, opt2: 2

키워드 목록 사용의 주요 단점은 부분 패턴 일치를 수행 할 수 없다는 것입니다.

iex(1)> m = %{a: 1, b: 2}
%{a: 1, b: 2}
iex(2)> %{a: a} = m
%{a: 1, b: 2}
iex(3)> a
1
iex(4)> k = [a: 1, b: 2]
[a: 1, b: 2]
iex(5)> [a: a] = k
** (MatchError) no match of right hand side value: [a: 1, b: 2]

함수 인수로 확장 해 보겠습니다. 옵션 중 하나의 값을 기반으로 다중 절 함수를 처리해야한다고 상상해보십시오.

def fun1(arg, opt1: opt1) when is_nil(opt1), do: do_special_thing
def fun1(arg, opts), do: do_regular_thing

def fun2(arg, %{opt1: opt1}) when is_nil(opt1), do: do_special_thing
def fun2(arg, opts), do: do_regular_thing

이것은 실행되지 않습니다 do_special_thing.

fun1("arg", opt1: nil, opt2: "some value")
doing regular thing

맵 인수를 사용하면 다음과 같이 작동합니다.

fun2("arg", %{opt1: nil, opt2: "some value"})
doing special thing


답변

맵은 특정 키에 대해 하나의 항목 만 허용하는 반면 키워드 목록에서는 키를 반복 할 수 있습니다. 맵은 효율적이며 (특히 성장함에 따라) Elixir의 패턴 매칭에 사용할 수 있습니다.

일반적으로 명령 줄 매개 변수 및 옵션 전달에 키워드 목록을 사용하고 연관 배열을 원할 때는 맵 (또는 다른 데이터 구조 인 HashDict)을 사용합니다.


답변