公海赌船710方的命令会自自然装 erlang 的环境。上面的通令会打定装 erlang 的环境。

模式匹配

  1. elixir 中 = 是模式匹配运算符
  2. 可以给list 的 head 和 tail 赋值

    iex> [h|t]=[1,2,3]
    [1, 2, 3]
    iex> h
    1
    iex> t
    [2, 3]
    

模块属性

elixir中模块的性质主要有3个意:

  1. 作为一个模块的诠释,通常附加上用户或编造机用到的信
  2. 作常量
  3. 当编译时作为一个临时的模块存储

列表速构

速构的意思啊尽管是由一个列表方便之成形另一个列表。

  1. 生成器

    iex> l = for n <- [1, 2, 4], do: n*n
    [1, 4, 16]
    iex> l
    [1, 4, 16]
    
  2. 过滤器

    iex> require Integer
    
    iex> for n <- 1..4, Integer.is_odd(n), do: n*n
    [1, 9]
    
  3. 其次进制转化为元组

    iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    
    iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
    [{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
    
  4. into

    • 去空格

      iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
      "helloworld"
      

字符串和字符列表

  1. 双引号包裹的是字符串: 字符串中储存的凡 byte
  2. 单引号包裹的是字符列表: 字符列表中存储的凡每个字符的 codepoint

安装

操纵语句

骨干运算符

  1. 算术运算 + – * / div/2 rem/2
  2. 列表拼接 ++ –
  3. 字符串拼接 <>

    iex> "foo" <> "bar"
    "foo" <> "bar"
    "foobar"
    
  4. 布尔运算符

    • or and not 这3个运算符只接受布尔值作为第一单参数

      iex> true or 1
      true or 1
      true
      
      iex> 1 or true
      1 or true
      ** (ArgumentError) argument error: 1
      
    • || && ! 这3只运算符可以接受非布尔值作为第一独参数

      iex> 1 || true
      1 || true
      1
      
      iex> true || 1
      true || 1
      true
      
  5. 较运算符
    = ! = !== <= >= < >

    • = != !== 相比,后者的检查更加严厉

      iex> 1 == 1.0
      1 == 1.0
      true
      
      iex> 1 === 1.0
      1 === 1.0
      false
      
      iex> 1 != 1.0
      1 != 1.0
      false
      
      iex> 1 !== 1.0
      1 !== 1.0
      true
      
    • 差数据类型之间为堪较大小

      iex> 1 < "hello"
      1 < "hello"
      true
      
      iex> 1 > "hello"
      1 > "hello"
      false
      
      iex> 1 < [1, 2]
      1 < [1, 2]
      true
      
      iex> "hello" < [1, 2]
      "hello" < [1, 2]
      false
      

      今非昔比数据类型之间的默认的逐一如下:

      number < atom < reference < functions < port < pid < tuple < maps < list < bitstring
      

列表速构

速构的意思啊就是自从一个列表方便之变更另一个列表。

  1. 生成器

    iex> l = for n <- [1, 2, 4], do: n*n
    [1, 4, 16]
    iex> l
    [1, 4, 16]
    
  2. 过滤器

    iex> require Integer
    
    iex> for n <- 1..4, Integer.is_odd(n), do: n*n
    [1, 9]
    
  3. 其次进制转化为元组

    iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    
    iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
    [{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
    
  4. into

    • 剔除空格

      iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
      "helloworld"
      

与方的枚举类型对应,流的处理是 懒惰 的,比如:

iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000

外表上看,和枚举类型的处理同,而事实上,流先创建了相同文山会海的计算操作。然后才当我们将其传递让Enum模块,它才会为调用。

iex> stream = 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000,
 funs: [#Function<23.27730995/1 in Stream.map/2>,
  #Function<8.27730995/1 in Stream.filter/2>]]>
iex> Enum.sum(stream)   <== 这里才开始执行
7500000000

常量

用作常量:

defmodule MyServer do
  @my_data 14
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

测试方法:

iex> MyServer.first_data
14

iex> MyServer.second_data
13

模块和函数定义方式

defmodule Math do
  def sum(a, b) do
    do_sum(a, b)
  end

  defp do_sum(a, b) do
    a + b
  end
end

Math.sum(1, 2)    #=> 3
Math.do_sum(1, 2) #=> ** (UndefinedFunctionError)

枚举类型和流

协议

谋类似于任何语言中之接口,谁促成了商谈,谁就是好使协议,
遵循下面的例证,Integer 和 User
结构体实现了协和,就足以使用协议中之方。

defmodule User do
  defstruct name: "harry", age: 32
end

defprotocol Enough do
  def enough?(data)
end

defimpl Enough, for: Integer do
  def enough?(data) do
    if data > 0 do
      true
    else
      false
    end
  end
end

defimpl Enough, for: User do
  def enough?(data) do
    if data.age > 18 do
      true
    else
      false
    end
  end
end

运示例:

iex> Enough.enough?(11)
true
iex> Enough.enough?(0)
false

iex> u = %User{}
%User{age: 32, name: "harry"}
iex> Enough.enough?(u)
true

iex> u = %{u|age: 10}
%User{age: 10, name: "harry"}
iex> Enough.enough?(u)
false

iex> Enough.enough?("string")
 ** (Protocol.UndefinedError) protocol Enough not implemented for "string"
    iex:3: Enough.impl_for!/1
    iex:4: Enough.enough?/1

面的 string 类型没有实现协议,所以不克采用。
咱于其实行使中为无会见对没有种档次且实现协议,为了避免出现异常,可以安装协议对负有种类的默认实现

defprotocol Enough do
  @fallback_to_any true
  def enough?(data)
end

defimpl Enough, for: Any do
  def enough?(_), do: false
end

然后,如下使用就不见面报错了

iex> Enough.enough?("string")
false

数学运算

iex> 1 / 2
1 / 2
0.5

/ 总是回到浮点数,如果要整数运算,使用 div 和 rem 函数

iex> div(1, 2)
div(1, 2)
0
iex> rem(1, 2)
rem(1, 2)
1

枚举类型

枚举类型提供了汪洋函数来对列表进行操作

iex> Enum.sum([1,2,3])
6
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.reduce(1..3, 0, &+/2)
6
iex> Enum.filter(1..3, &(rem(&1, 2) != 0))
[1, 3]

枚举操作都是主动的,比如如下的操作:

iex> odd? = &(rem(&1, 2) != 0)
#Function<6.54118792/1 in :erl_eval.expr/5>

iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000

以上每步的操作(Enum.map, Enum.filter)都见面时有发生一个初的列表,这虽是
积极 的意思。

模块和函数定义方式

defmodule Math do
  def sum(a, b) do
    do_sum(a, b)
  end

  defp do_sum(a, b) do
    a + b
  end
end

Math.sum(1, 2)    #=> 3
Math.do_sum(1, 2) #=> ** (UndefinedFunctionError)

函数中之哨兵表达式

defmodule Math do
  def zero?(0) do
    true
  end

  def zero?(x) when is_number(x) do
    false
  end
end

Math.zero?(0)  #=> true
Math.zero?(1)  #=> false

Math.zero?([1,2,3])
#=> ** (FunctionClauseError)

列表和元组区别

  1. 列表是坐链表形式在内存存储的,元组是于内存中老是存储的。
  2. 列表前置拼接操作便捷,后置拼接操作慢
    后置拼接时修改了原先列表的最终一个要素,所以会见重建总体列表
  3. 函数的返回值一般用元组来保存

中心数据类

iex> 1          # integer
iex> 0x1F       # integer
iex> 1.0        # float
iex> true       # boolean
iex> :atom      # atom / symbol
iex> "elixir"   # string
iex> [1, 2, 3]  # list
iex> {1, 2, 3}  # tuple

同方的枚举类型对应,流的拍卖是 懒惰 的,比如:

iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000

外表上看,和枚举类型的拍卖同,而其实,流先创建了平等多元之测算操作。然后就当我们把它传递给Enum模块,它才会让调用。

iex> stream = 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000,
 funs: [#Function<23.27730995/1 in Stream.map/2>,
  #Function<8.27730995/1 in Stream.filter/2>]]>
iex> Enum.sum(stream)   <== 这里才开始执行
7500000000

默认参数

defmodule Concat do
  def join(a, b, sep \\ " ") do
    a <> sep <> b
  end
end

IO.puts Concat.join("Hello", "world")      #=> Hello world
IO.puts Concat.join("Hello", "world", "_") #=> Hello_world

骨干运算符

  1. 算术运算 + – * / div/2 rem/2
  2. 列表拼接 ++ –
  3. 字符串拼接 <>

    iex> "foo" <> "bar"
    "foo" <> "bar"
    "foobar"
    
  4. 布尔运算符

    • or and not 这3独运算符只接受布尔值作为第一个参数

      iex> true or 1
      true or 1
      true
      
      iex> 1 or true
      1 or true
      ** (ArgumentError) argument error: 1
      
    • || && ! 这3单运算符可以领非布尔值作为第一只参数

      iex> 1 || true
      1 || true
      1
      
      iex> true || 1
      true || 1
      true
      
  5. 比运算符
    = ! = !== <= >= < >

    • = != !== 相比,后者的自我批评更加严峻

      iex> 1 == 1.0
      1 == 1.0
      true
      
      iex> 1 === 1.0
      1 === 1.0
      false
      
      iex> 1 != 1.0
      1 != 1.0
      false
      
      iex> 1 !== 1.0
      1 !== 1.0
      true
      
    • 不同数据类型之间也足以比较大小

      iex> 1 < "hello"
      1 < "hello"
      true
      
      iex> 1 > "hello"
      1 > "hello"
      false
      
      iex> 1 < [1, 2]
      1 < [1, 2]
      true
      
      iex> "hello" < [1, 2]
      "hello" < [1, 2]
      false
      

      不等数据类型之间的默认的各个如下:

      number < atom < reference < functions < port < pid < tuple < maps < list < bitstring
      

字符串和字符列表

  1. 双引号包裹的凡字符串: 字符串中贮存的凡 byte
  2. 单引号包裹的是字符列表: 字符列表中蕴藏的凡每个字符的 codepoint

键值列表

iex> l = [{:a, 1},{:b, 2}]
[a: 1, b: 2]
iex> l[:a]
1

iex> l[:b]
2

键值列表还有其余一样种植概念方式:(注意 a: 和 1 之间必须发只空格)

iex> l = [a: 1, b: 2]
[a: 1, b: 2]

键值列表2只特征:

  1. 有序
  2. key 可以又,重复时,优先获得排在前头的key

    iex> l = [a: 3] ++ l;
    [a: 3, a: 1, b: 2]
    iex> l
    [a: 3, a: 1, b: 2]
    iex> l[:a]
    3

cond

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...>   3 + 3 == 6 ->
...>     "But this will too"
...> end
"But this will"

仅仅见面实行第一只门当户对上之支行

结构体

  1. 定义

    defmodule User do
      defstruct name: "harry", age: 32
    end
    
  2. 使方式

    iex> j = %User{}
    %User{age: 32, name: "harry"}
    
    iex> j.name
    "harry"
    
    iex> j[:name]
    ** (UndefinedFunctionError) undefined function User.fetch/2
                 User.fetch(%User{age: 32, name: "harry"}, :name)
        (elixir) lib/access.ex:77: Access.get/3
    
    iex> j.__struct__
    User
    

do

do 语句快出2种植写法:

iex> if true do
...> "this is true"
...> else
...> "this is false"
...> end

OR

iex> if true, do: ("this is true"), else: ("this is false")

图的2个特点:

  1. 祈求中的key是无序的
  2. 希冀的key可以是任意档次

    iex> map = %{:a => 1, 2 => :b}
    %{2 => :b, :a => 1}

图匹配时,只要 = 右边包含左边的值就能配合配上

iex> %{} = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}

iex> %{:a => 1, 2 => :b} = %{}
    ** (MatchError) no match of right hand side value: %{}

iex> %{:a => 1} = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}

iex> %{:a => 1, :c => 2} = %{:a => 1, 2 => :b}
   ** (MatchError) no match of right hand side value: %{2 => :b, :a => 1}

修改图中之值好就此以下的方法:

iex> %{map | 2 => :c}
%{2 => :c, :a => 1}

注释

诠释时,一些常用之模块属性如下:

名称 含义
@moduledoc 为当前模块提供文档
@doc 为该属性后面的函数或宏提供文档
@behaviour (注意这个单词是英式拼法)用来注明一个OTP或用户自定义行为
@before\_compile 提供一个每当模块被编译之前执行的钩子。这使得我们可以在模块被编译之前往里面注入函数。

模块和函数定义

case

iex> case {1, 2, 3} do
...>   {4, 5, 6} ->
...>     "This clause won't match"
...>   {1, x, 3} ->
...>     "This clause will match and bind x to 2 in this clause"
...>   _ ->
...>     "This clause would match any value"
...> end

case的原则中可以在判断的表达式,比如下面的 (when x > 0)

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Won't match"
...> end

列表

  1. 列表中得分包自由数据类型

    iex> [1, 1.2, true, "hello"]
    [1, 1.2, true, "hello"]
    [1, 1.2, true, "hello"]
    
  2. 列表可以透过 ++/– 来拼接

    iex> [1, 2, true] ++ [1, 3, false]
    [1, 2, true] ++ [1, 3, false]
    [1, 2, true, 1, 3, false]
    
    iex> [1, 2, true, 2, false] -- [1, 3, false, 2]
    [1, 2, true, 2, false] -- [1, 3, false, 2]
    [true, 2]
    
  3. 可以通过 hd/1 tl/1 函数来得到头部及首以外的一部分

    iex> hd([1, 2, true])
    hd([1, 2, true])
    1
    
    iex> tl([1, 2, true])
    tl([1, 2, true])
    [2, true]
    
  4. 对一个空列表执行 hd/1 和 tl/1 会报错

    iex> hd([])
    hd([])
    ** (ArgumentError) argument error
        :erlang.hd([])
    
    iex> tl([])
    tl([])
    ** (ArgumentError) argument error
        :erlang.tl([])
    

数学运算

iex> 1 / 2
1 / 2
0.5

/ 总是回到浮点数,如果要整数运算,使用 div 和 rem 函数

iex> div(1, 2)
div(1, 2)
0
iex> rem(1, 2)
rem(1, 2)
1

原子

原子是千篇一律种常量,变量名就是是它的值。有2种植写法:

  1. :原子名
  2. :”原子名”

模块和函数定义

默认参数

defmodule Concat do
  def join(a, b, sep \\ " ") do
    a <> sep <> b
  end
end

IO.puts Concat.join("Hello", "world")      #=> Hello world
IO.puts Concat.join("Hello", "world", "_") #=> Hello_world

if/unless

iex> if nil do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

unless 和 if 相反,条件吧false时才行

iex> unless true do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

起定义格外

于定义格外使用 defexception/1 函数,

iex> h(defexception)
The most common way to raise an exception is via raise/2:

┃ defmodule MyAppError do
┃   defexception [:message]
┃ end
┃
┃ value = [:hello]
┃
┃ raise MyAppError,
┃   message: "did not get what was expected, got: #{inspect value}"

In many cases it is more convenient to pass the expected value to raise/2 and
generate the message in the exception/1 callback:

┃ defmodule MyAppError do
┃   defexception [:message]
┃
┃   def exception(value) do
┃     msg = "did not get what was expected, got: #{inspect value}"
┃     %MyAppError{message: msg}
┃   end
┃ end
┃
┃ raise MyAppError, value

The example above shows the preferred strategy for customizing exception
messages.

列表

  1. 列表中好分包自由数据类型

    iex> [1, 1.2, true, "hello"]
    [1, 1.2, true, "hello"]
    [1, 1.2, true, "hello"]
    
  2. 列表可以由此 ++/– 来拼接

    iex> [1, 2, true] ++ [1, 3, false]
    [1, 2, true] ++ [1, 3, false]
    [1, 2, true, 1, 3, false]
    
    iex> [1, 2, true, 2, false] -- [1, 3, false, 2]
    [1, 2, true, 2, false] -- [1, 3, false, 2]
    [true, 2]
    
  3. 得经过 hd/1 tl/1 函数来获得头部及首以外的片段

    iex> hd([1, 2, true])
    hd([1, 2, true])
    1
    
    iex> tl([1, 2, true])
    tl([1, 2, true])
    [2, true]
    
  4. 对一个空列表执行 hd/1 和 tl/1 会报错

    iex> hd([])
    hd([])
    ** (ArgumentError) argument error
        :erlang.hd([])
    
    iex> tl([])
    tl([])
    ** (ArgumentError) argument error
        :erlang.tl([])
    

if/unless

iex> if nil do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

unless 和 if 相反,条件吧false时才实施

iex> unless true do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

次进制,八进制,十六进制表示方法

iex> 0b10000
0b10000
16
iex> 0o20
0o20
16
iex> 0x10
0x10
16

函数中之哨兵表达式

defmodule Math do
  def zero?(0) do
    true
  end

  def zero?(x) when is_number(x) do
    false
  end
end

Math.zero?(0)  #=> true
Math.zero?(1)  #=> false

Math.zero?([1,2,3])
#=> ** (FunctionClauseError)

键值列表-图-字典

cond

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...>   3 + 3 == 6 ->
...>     "But this will too"
...> end
"But this will"

唯有会尽第一只相当上的子

结构体

  1. 定义

    defmodule User do
      defstruct name: "harry", age: 32
    end
    
  2. 动用办法

    iex> j = %User{}
    %User{age: 32, name: "harry"}
    
    iex> j.name
    "harry"
    
    iex> j[:name]
    ** (UndefinedFunctionError) undefined function User.fetch/2
                 User.fetch(%User{age: 32, name: "harry"}, :name)
        (elixir) lib/access.ex:77: Access.get/3
    
    iex> j.__struct__
    User
    

进程

elixir中经过都是轻量级的,所以用时绝不太在一齐进程的数据。

  1. 派生的历程执行完毕自动终止自己

    iex> pid = spawn fn -> 1 + 2 end
    #PID<0.62.0>
    iex> Process.alive?(pid)
    false
    
  2. 发送和收信息
    下示例中凡吃好发送了一致久信息,可以由此 flush/1
    函数刷新消息,刷新一破下虽

    iex> send self(), {:hello, "world"}
    {:hello, "world"}
    iex> flush
    {:hello, "world"}
    :ok
    iex> flush
    :ok
    

    啊足以经过 receive/1 函数来接收

    iex> send self(), {:hello, "world"}
    {:hello, "world"}
    iex> receive do
    ...> {:hi, msg} -> msg
    ...> {:hello, msg} -> msg
    ...> end
    "world"
    

    receive/1 函数了不顶消息会阻塞,可以让它们装一个过期时间

    iex> receive do
    ...> {:hello, msg} -> msg
    ...> after
    ...> 3000 -> "timeout"
    ...> end
    "timeout"
    
  3. 过程之中的连日
    经过B连接进程A之后,进程A出现异常,进程B就可知捕获,这样经过B就能够处理进程A的大
    过程连接的章程特别简短,就是 spawn_link/1 函数

    iex> spawn fn -> raise "oops" end
    #PID<0.76.0>
    
    15: 18:22.804 [error] Process #PID<0.76.0> raised an exception
    ** (RuntimeError) oops
    :erlang.apply/2
    
    iex> spawn_link fn -> raise "oops" end
    ** (EXIT from #PID<0.73.0>) an exception was raised:
    ** (RuntimeError) oops
    :erlang.apply/2
    
    15: 18:31.533 [error] Process #PID<0.78.0> raised an exception
     ** (RuntimeError) oops
     :erlang.apply/2
    

    关注
    Process模块
    模块,里面提供了经过操作的函数

  4. 进程面临保存状态的措施:

    defmodule KV do
      def start do
        {:ok, spawn_link(fn -> loop(%{}) end)}
      end
    
      defp loop(map) do
        receive do
          {:get, key, caller} ->
            send caller, Map.get(map, key)
            loop(map)
          {:put, key, value} ->
            loop(Map.put(map, key, value))
        end
      end
    end
    
    iex> send pid, {:put, :hello, :world}
    #PID<0.62.0>
    iex> send pid, {:get, :hello, self()}
    {:get, :hello, #PID<0.41.0>}
    iex> flush
    :world
    

    事实上应用时,可以用 Agent
    模块
    来简化上面的操作。

列表和元组区别

  1. 列表是因链表形式在内存存储的,元组是于内存中老是存储的。
  2. 列表前置拼接操作便捷,后置拼接操作慢
    后置拼接时修改了原先列表的结尾一个元素,所以会重建总体列表
  3. 函数的返回值一般用元组来保存

MAC 平台用 brew 安装

brew update
brew install elixir

要无 erlang 环境,上面的一声令下会打定装 erlang 的环境。

进程

elixir中经过都是轻量级的,所以使用时不用太在一齐进程的数码。

  1. 派生的经过执行了自动终止自己

    iex> pid = spawn fn -> 1 + 2 end
    #PID<0.62.0>
    iex> Process.alive?(pid)
    false
    
  2. 出殡和接受信息
    脚示例中凡是为协调发送了相同修信息,可以经 flush/1
    函数刷新消息,刷新一不良后便

    iex> send self(), {:hello, "world"}
    {:hello, "world"}
    iex> flush
    {:hello, "world"}
    :ok
    iex> flush
    :ok
    

    也得由此 receive/1 函数来接受

    iex> send self(), {:hello, "world"}
    {:hello, "world"}
    iex> receive do
    ...> {:hi, msg} -> msg
    ...> {:hello, msg} -> msg
    ...> end
    "world"
    

    receive/1 函数了不交消息会阻塞,可以为其装一个过时间

    iex> receive do
    ...> {:hello, msg} -> msg
    ...> after
    ...> 3000 -> "timeout"
    ...> end
    "timeout"
    
  3. 进程之中的总是
    过程B连接进程A之后,进程A出现异常,进程B就会捕获,这样经过B就会处理进程A的异常
    过程连接的点子非常简短,就是 spawn_link/1 函数

    iex> spawn fn -> raise "oops" end
    #PID<0.76.0>
    
    15: 18:22.804 [error] Process #PID<0.76.0> raised an exception
    ** (RuntimeError) oops
    :erlang.apply/2
    
    iex> spawn_link fn -> raise "oops" end
    ** (EXIT from #PID<0.73.0>) an exception was raised:
    ** (RuntimeError) oops
    :erlang.apply/2
    
    15: 18:31.533 [error] Process #PID<0.78.0> raised an exception
     ** (RuntimeError) oops
     :erlang.apply/2
    

    关注
    Process模块
    模块,里面提供了经过操作的函数

  4. 过程遭到保存状态的方:

    defmodule KV do
      def start do
        {:ok, spawn_link(fn -> loop(%{}) end)}
      end
    
      defp loop(map) do
        receive do
          {:get, key, caller} ->
            send caller, Map.get(map, key)
            loop(map)
          {:put, key, value} ->
            loop(Map.put(map, key, value))
        end
      end
    end
    
    iex> send pid, {:put, :hello, :world}
    #PID<0.62.0>
    iex> send pid, {:get, :hello, self()}
    {:get, :hello, #PID<0.41.0>}
    iex> flush
    :world
    

    实则使用时,可以用 Agent
    模块
    来简化上面的操作。

很的以

elixir 虽然提供了 try/catch/rescue/after
的组织,但是尽量不要采取这种布局,使用这种大处理方式,会影响现有程序的拍卖流程。
elixir
的过多函数都见面回错误信号,通过信号来处理错误是援引的法门(类似golang的错误处理),比如如下示例:

iex> case File.read "hello" do
...>   {:ok, body} -> IO.puts "got ok"
...>   {:error, body} -> IO.puts "got error"
...> end

怪的行使

elixir 虽然提供了 try/catch/rescue/after
的构造,但是尽量不要用这种组织,使用这种好处理方式,会潜移默化现有程序的拍卖流程。
elixir
的浩大函数都见面回到错误信号,通过信号来处理错误是推荐的法子(类似golang的错误处理),比如如下示例:

iex> case File.read "hello" do
...>   {:ok, body} -> IO.puts "got ok"
...>   {:error, body} -> IO.puts "got error"
...> end

核心数据类

iex> 1          # integer
iex> 0x1F       # integer
iex> 1.0        # float
iex> true       # boolean
iex> :atom      # atom / symbol
iex> "elixir"   # string
iex> [1, 2, 3]  # list
iex> {1, 2, 3}  # tuple

模块属性

elixir中模块的特性主要发生3只意:

  1. 用作一个模块的笺注,通常附加上用户或编造机用到之音讯
  2. 当常量
  3. 于编译时作一个临时之模块存储

枚举类型

枚举类型提供了汪洋函数来对列表进行操作

iex> Enum.sum([1,2,3])
6
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.reduce(1..3, 0, &+/2)
6
iex> Enum.filter(1..3, &(rem(&1, 2) != 0))
[1, 3]

枚举操作都是主动的,比如如下的操作:

iex> odd? = &(rem(&1, 2) != 0)
#Function<6.54118792/1 in :erl_eval.expr/5>

iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000

以上每步的操作(Enum.map, Enum.filter)都见面有一个初的列表,这虽是
积极 的意思。

异常处理

case

iex> case {1, 2, 3} do
...>   {4, 5, 6} ->
...>     "This clause won't match"
...>   {1, x, 3} ->
...>     "This clause will match and bind x to 2 in this clause"
...>   _ ->
...>     "This clause would match any value"
...> end

case的条件被好进入判断的表达式,比如下面的 (when x > 0)

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Won't match"
...> end

打定义格外

起定义格外使用 defexception/1 函数,

iex> h(defexception)
The most common way to raise an exception is via raise/2:

┃ defmodule MyAppError do
┃   defexception [:message]
┃ end
┃
┃ value = [:hello]
┃
┃ raise MyAppError,
┃   message: "did not get what was expected, got: #{inspect value}"

In many cases it is more convenient to pass the expected value to raise/2 and
generate the message in the exception/1 callback:

┃ defmodule MyAppError do
┃   defexception [:message]
┃
┃   def exception(value) do
┃     msg = "did not get what was expected, got: #{inspect value}"
┃     %MyAppError{message: msg}
┃   end
┃ end
┃
┃ raise MyAppError, value

The example above shows the preferred strategy for customizing exception
messages.

字典

以上的 键值列表 和 图 都是 字典 ,它们都实现了 Dict 接口。
本条模块现在曾 deprecated

常量

当常量:

defmodule MyServer do
  @my_data 14
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

测试方法:

iex> MyServer.first_data
14

iex> MyServer.second_data
13

sigils(魔法印)

sigils 也就是指向都部分变量或者常量做有记,使之变成其他的物。
sigils 的目的就是是增高 elixir 语言的扩展性。

  1. 正则表达式中的使

    iex> regex = ~r/foo|bar/
    ~r/foo|bar/
    
    iex> "foo" =~ regex
    true
    
    iex> "bat" =~ regex
    false
    
  2. 代表字符串,字符以及列表的以身作则

    iex> ~s(this is a string with "quotes")
    "this is a string with \"quotes\""
    
    iex> ~c(this is a string with "quotes")
    'this is a string with "quotes"'
    
    iex> ~w(foo bar bat)
    ["foo", "bar", "bat"]
    

    ~w 还可加入另外的修饰符(比如:c, s, a
    分别表示字符列表,字符串,原子)

    iex> ~w(foo bar bat)a
    [:foo, :bar, :bat]
    
  3. 自定义 sigils

    iex> defmodule MySigils do
    ...> def sigil_i(string, []), do: string <> "add_sigil"
    ...> end
    
    iex> import MySigils
    iex> ~i("123")
    

字典

以上的 键值列表 和 图 都是 字典 ,它们都落实了 Dict 接口。
其一模块现在曾经 deprecated

注释

注解时,一些常用的模块属性如下:

名称 含义
@moduledoc 为当前模块提供文档
@doc 为该属性后面的函数或宏提供文档
@behaviour (注意这个单词是英式拼法)用来注明一个OTP或用户自定义行为
@before\_compile 提供一个每当模块被编译之前执行的钩子。这使得我们可以在模块被编译之前往里面注入函数。

原子

原子是平等种常量,变量名就是她的价值。有2种写法:

  1. :原子名
  2. :”原子名”

即存储

模块中之变量只以编译时存在,所以用做现存储,存储一些仅仅当编译时用的变量。
示例:

defmodule MyServer do
  @my_data 14
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

iex> MyServer.first_data #=> 14
iex> MyServer.second_data #=> 13

图的2个特点:

  1. 图被之key是无序的
  2. 祈求的key可以是擅自档次

    iex> map = %{:a => 1, 2 => :b}
    %{2 => :b, :a => 1}

贪图匹配时,只要 = 右边包含左边的值就是能够匹配配上

iex> %{} = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}

iex> %{:a => 1, 2 => :b} = %{}
    ** (MatchError) no match of right hand side value: %{}

iex> %{:a => 1} = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}

iex> %{:a => 1, :c => 2} = %{:a => 1, 2 => :b}
   ** (MatchError) no match of right hand side value: %{2 => :b, :a => 1}

改图被的价好为此以下的法:

iex> %{map | 2 => :c}
%{2 => :c, :a => 1}

死处理

键值列表

iex> l = [{:a, 1},{:b, 2}]
[a: 1, b: 2]
iex> l[:a]
1

iex> l[:b]
2

键值列表还有其它一样种概念方式:(注意 a: 和 1 之间必须来个空格)

iex> l = [a: 1, b: 2]
[a: 1, b: 2]

键值列表2单特色:

  1. 有序
  2. key 可以另行,重复时,优先获得排在前边的key

    iex> l = [a: 3] ++ l;
    [a: 3, a: 1, b: 2]
    iex> l
    [a: 3, a: 1, b: 2]
    iex> l[:a]
    3

协议

商事类似于其他语言中的接口,谁促成了商谈,谁就可下协议,
随下面的例证,Integer 和 User
结构体实现了商事,就得应用协议中之方。

defmodule User do
  defstruct name: "harry", age: 32
end

defprotocol Enough do
  def enough?(data)
end

defimpl Enough, for: Integer do
  def enough?(data) do
    if data > 0 do
      true
    else
      false
    end
  end
end

defimpl Enough, for: User do
  def enough?(data) do
    if data.age > 18 do
      true
    else
      false
    end
  end
end

使用示例:

iex> Enough.enough?(11)
true
iex> Enough.enough?(0)
false

iex> u = %User{}
%User{age: 32, name: "harry"}
iex> Enough.enough?(u)
true

iex> u = %{u|age: 10}
%User{age: 10, name: "harry"}
iex> Enough.enough?(u)
false

iex> Enough.enough?("string")
 ** (Protocol.UndefinedError) protocol Enough not implemented for "string"
    iex:3: Enough.impl_for!/1
    iex:4: Enough.enough?/1

点的 string 类型没有实现协议,所以无克用。
咱们当其实运用中为无会见对没有种档次且实现协议,为了避免出现异常,可以装协议对拥有种类的默认实现

defprotocol Enough do
  @fallback_to_any true
  def enough?(data)
end

defimpl Enough, for: Any do
  def enough?(_), do: false
end

这么后,如下使用就未会见报错了

iex> Enough.enough?("string")
false

临时存储

模块中的变量只当编译时是,所以用做现存储,存储一些仅仅在编译时利用的变量。
示例:

defmodule MyServer do
  @my_data 14
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

iex> MyServer.first_data #=> 14
iex> MyServer.second_data #=> 13

第二进制,八进制,十六进制表示方法

iex> 0b10000
0b10000
16
iex> 0o20
0o20
16
iex> 0x10
0x10
16

枚举类型和流

do

do 语句快生2栽写法:

iex> if true do
...> "this is true"
...> else
...> "this is false"
...> end

OR

iex> if true, do: ("this is true"), else: ("this is false")

MAC 平台用 brew 安装

brew update
brew install elixir

倘没 erlang 环境,上面的吩咐会起自然装 erlang 的条件。

键值列表-图-字典

sigils(魔法印)

sigils 也尽管是对准曾经有些变量或者常量做一些标志,使之变成其他的事物。
sigils 的目的就是是增进 elixir 语言的扩展性。

  1. 正则表达式中之使用

    iex> regex = ~r/foo|bar/
    ~r/foo|bar/
    
    iex> "foo" =~ regex
    true
    
    iex> "bat" =~ regex
    false
    
  2. 表示字符串,字符以及列表的演示

    iex> ~s(this is a string with "quotes")
    "this is a string with \"quotes\""
    
    iex> ~c(this is a string with "quotes")
    'this is a string with "quotes"'
    
    iex> ~w(foo bar bat)
    ["foo", "bar", "bat"]
    

    ~w 还好进入另外的修饰符(比如:c, s, a
    分别表示字符列表,字符串,原子)

    iex> ~w(foo bar bat)a
    [:foo, :bar, :bat]
    
  3. 自定义 sigils

    iex> defmodule MySigils do
    ...> def sigil_i(string, []), do: string <> "add_sigil"
    ...> end
    
    iex> import MySigils
    iex> ~i("123")
    

模式匹配

  1. elixir 中 = 是模式匹配运算符
  2. 可以给list 的 head 和 tail 赋值

    iex> [h|t]=[1,2,3]
    [1, 2, 3]
    iex> h
    1
    iex> t
    [2, 3]
    

支配语句

安装

相关文章