ElixirのDataType


Elixir 1.1.0-dev(2014年11月24日)で確認
テスト用コードを[ryuone/ablation](https://github.com/ryuone/ablation)に作成

# DataType

## Integers
* decimal

        128 / 1_000_000

* hexadecimal

        0x1f

* octal

        0o765

* binary

        0b1010

## Floating point numbers

* floating

        1.0
        0.2456
        0.314e1
        314.0e-2

## Range
    iex> range = 1..10
    iex> Enum.map range, &(&1 + 2)
    [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

## Regular expressions
    iex> reg = ~r{(\d*)}i
    iex> Regex.run reg, "123abc"
    ["123", "123"]

## Pid
    pid = self

## Ports
    iex> pid = Port.open({:spawn, "date"}, [:binary, :stderr_to_stdout, :exit_status])
    #Port<0.1606>
    iex> flush
    {#Port<0.1606>, {:data, "2014年 9月 7日 日曜日 10時55分26秒 JST\n"}}
    {#Port<0.1606>, {:exit_status, 0}}

## Atoms
    :foo
    :me@localhost
    :"with spaces"
    :'with spaces'
    :<>
    :===

## Tuples
    {1, 2}
    {:ok, {:name, "elixir"}}
    {:error, :enoent}
    iex> {status, count, action} = {:ok, 42, "next"}
    iex> status
    :ok

## Records
Records are simply tuples where the first element is an atom.

    iex> require Record
    iex> defmodule User do
       >   Record.defrecord :user, [name: "ryuone", status: :ok]
       > end
    iex> require User
    iex> User.user
    {:user, "ryuone", :ok}
    iex> ryuone = User.user status: :not_ok
    {:user, "ryuone", :not_ok}
    iex> elem ryuone, 0
    :user
    iex> elem ryuone, 2
    : not_ok
    iex> User.user ryuone, :name
    "ryuone"
    iex> ryuone2 = User.user "ryuone", height: 160
    {:user, "ryuone", :fine}

## Lists
    iex> [1, 2, 3, 4]
    [1, 2, 3, 4]
    iex> [1, 2, 3, 4] ++ [1, 2, 3]
    [1, 2, 3, 4, 1, 2, 3]
    iex> [1, 2, 3, 4] -- [1, 2, 3]
    [4]
    iex> 1 in [1, 2, 3, 4]
    true

## Keyword list
    iex> kwlist = Keyword.new name: "ryuone", status: :ok
    iex> :io.format "~p~n", [kwlist]
    [{status,ok},{name,<<"ryuone">>}]

    iex> Keyword.get kwlist, :name
    "ryuone"
    iex> Keyword.keys kwlist
    [:status, :name]
    iex> Keyword.values kwlist
    [:ok, "ryuone"]
    iex> Keyword.put kwlist, :name, :ryuone
    [name: :ryuone, status: :ok]


## Maps

    iex> pref = %{ "Tokyo" => "東京", "Osaka" => "大阪" }
    %{"Osaka" => "大阪", "Tokyo" => "東京"}
    iex> pref["Osaka"]
    "大阪"

    iex> type = %{ [name: "A"] => "Name A", [name: "B"] => "Name B" }
    iex> type[[name: "A"]]
    "Name A"
    iex> %{[name: "B"] => b} = type
    %{[name: "A"] => "Name A", [name: "B"] => "Name B"}
    iex> b
    "Name B"
    iex> pref = %{ :tokyo => "東京", :osaka => "大阪" }
    iex> pref.tokyo
    "東京"

    # Update
    iex> pref2 = %{pref | :tokyo => "東京都"}
    %{osaka: "大阪", tokyo: "東京都"}
    iex> %{pref | :tokyo_to => "東京都"}
    ** (CompileError) iex:2: illegal map key

## HashDict(Using Dict module)
Maps and HashDicts both implement the Dict behaviour.

    iex> hashdict = [ one: 1, two: 2, three: 3 ] |> Enum.into HashDict.new
    #HashDict<[two: 2, one: 1, three: 3]>
    iex> map      = %{four: 4, file: 5, six: 6}
    %{file: 5, four: 4, six: 6}

    iex> hashdict |> Dict.values |> Enum.sum
    6
    iex> map      |> Dict.values |> Enum.sum
    15

    iex> kwlist = [name: "ryuone", status: :ok, country: "Japan"]
    iex> hashdict = kwlist |> Enum.into HashDict.new
    iex> map      = kwlist |> Enum.into Map.new
    iex> hashdict[:name]
    "ryuone"
    iex> map[:name]
    "ryuone"
    iex> map = Dict.put map, :lang, "Node.js"
    %{country: "Japan", lang: "Node.js", name: "ryuone", status: :ok}
    iex> merge = Dict.merge(map, hashdict)
    %{country: "Japan", lang: "Node.js", name: "ryuone", status: :ok}

## HashSet(Using Set module)

    iex> set1 = Enum.into 1..5, HashSet.new
    #HashSet<[2, 3, 4, 1, 5]>
    iex> Set.member? set1, 3
    true
    iex> set2 = Enum.into 4..8, HashSet.new
    #HashSet<[7, 6, 4, 5, 8]>
    iex> Set.union set1, set2
    #HashSet<[7, 6, 2, 4, 3, 5, 1, 8]>
    iex> Set.difference set1, set2
    #HashSet<[2, 3, 1]>
    iex> Set.difference set2, set1
    #HashSet<[7, 6, 8]>

    iex> Set.intersection set1, set2
    #HashSet<[4, 5]>

## Binaries

    iex(71)> bin = << 65,  66, 97, 98 >>
    "ABab"
    iex> String.length bin
    4
    iex> bin = <<3 :: size(2), 5 :: size(4), 1 :: size(2)>>
    <<213>>
    iex> :io.format "~-8.2b~n", :binary.bin_to_list bin
    11010101
    iex> String.length bin
    1
    iex> <<hello::binary-size(5), rest::binary>> = "Hello world"
    "Hello world"
    iex> rest
    " world"

## Struct

```elixir
defmodule User do
  defstruct name: "", status: :dont_know
end
```

    iex> %User{}
    %User{name: "", status: :dont_know}
    iex> %User{name: "ryuone"}
    %User{name: "ryuone", status: :dont_know}
    iex> %User{name: "ryuone", status: :ok}
    %User{name: "ryuone", status: :ok}

    # Struct Update(like Map)
    iex> ryuone = %User{name: "ryuone", status: :ok}
    %User{name: "ryuone", status: :ok}
    iex> ryuone2 = %{ryuone | name: "ryuone2"}
    %User{name: "ryuone2", status: :ok}

    iex> %User{name: name} = ryuone
    iex> name
    "ryuone"

    iex> ryuone[:name]
    ** (Protocol.UndefinedError) protocol Access not implemented for %User{name: "ryuone", status: :ok}

    iex> Dict.get(%User{}, :name)
    ** (UndefinedFunctionError) undefined function: User.get/3

## Protocols

* Define protocol

```elixir
defprotocol Inspect do
  def inspect(thing, opts)
end
```

* Implement a protocol

```elixir
defimpl Inspect, for: PID do
  def inspect(pid, _opts) do
    "my#PID" <> List.to_string(:erlang.pid_to_list(pid))
  end
end
defimpl Inspect, for: Reference do
  def inspect(ref, _opts) do
    '#Ref' ++ rest = :erlang.ref_to_list(ref)
    "#Reference" <> List.to_string(rest)
  end
end
```

* Struct

```elixir
defmodule User do
  defstruct name: "", status: :dont_know
end

defprotocol Blank do
  @doc "Returns true if data is considered blank/empty"
  def blank?(data)
end

defimpl Blank, for: User do
  def blank?(%User{name: ""} = user) do
    true
  end
  def blank?(%User{name: _} = user) do
    false
  end
end
```

    iex> Blank.blank? %User{}
    true
    iex> Blank.blank? %User{name: "ryuone"}
    false

---

# 以下メモ

## proplist / keyword list relation.

### proplist and keyword list are same

* Erlang

        erl> List = [{a, "a"}, {b, "a"}].
        [{a,"a"},{b,"a"}]
        erl> proplists:get_value(a, List).
        "a"

* Elixir

        iex> kwlist=[{:a,"a"},{:b,"a"}]
        [a: "a", b: "a"]
        iex> Keyword.get kwlist, :a
        "a"

---
## Etc.

### Operator

| Erlang         | Elixir         | Meaning                                 |
|----------------|----------------|-----------------------------------------|
| and            | NOT AVAILABLE  | Logical 'and', evaluates both arguments |
| andalso        | and            | Logical 'and', short-circuits           |
| or             | NOT AVAILABLE  | Logical 'or', evaluates both arguments  |
| orelse         | or             | Logical 'or', short-circuits            |
| =:=            | ===            | A match operator                        |
| =/=            | !==            | A negative match                        |
| /=             | !=             | Not equals                              |
| =<             | <=             | Less than or equals                     |