엘릭서에는지도가 있습니다 :
> 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에 키 / 값 쌍을 저장해야하는 경우에도 다음 옵션이 있습니다.
¹ 일반적으로 말하지만 물론 다릅니다 ™.
² 가장 좋은 경우는 목록 앞에 추가하는 것입니다.
³ 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)을 사용합니다.