提供基本语法和方法的 Elixir 快速参考备忘单。
每个操作系统的安装说明可以在 elixir-lang.org 网站上 Installing Elixir 部分找到。
Elixir 自带了iex
这样一个交互 shell,可以随时计算 Elixir 表达式的值,运行iex
命令,继续输入几个简单的表达式试试:
iex 2+3
5
iex 2+3 == 5
true
iex String.length("The quick brown fox jumps over the lazy dog")
43
IO.puts("Hello world from Elixir")
Elixir 运行命令
$ elixir hello.exs
Elixir 支持多种基本类型:整数、浮点、布尔值、原子和字符串。其他数据类型,如列表和元组
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 + 2
3
iex> 5 * 5
25
iex> 10 / 2
5.0
运算符
/
总是返回一个float。如果你想做整数除法或得到除法余数,你可以调用div和rem函数:
iex> div(10, 2)
5
iex> div 10, 2 # Elixir允许在调用需要一个或多个参数的函数时删除括号
5
iex> rem 10, 3
1
可以调用round函数来获取与给定浮点数最接近的整数,或者调用trunc函数来获取浮点数的整数部分
iex> round(3.58)
4
iex> trunc(3.58)
3
可以使用is_integer、is_float或is_number分别检查参数是否为integer、float或number类型
iex> is_integer(1)
true
iex> is_float(2.0)
true
iex> is_number(2.0)
false
Elixir 提供了
||
、&&
和!
布尔操作符,它们支持任何类型的操作:
iex> -20 || true
-20
iex> false || 42
42
iex> 42 && true
true
iex> 42 && nil
nil
iex> !42
false
iex> !false
true
还有三个操作符(and、or、not),它们的第一个参数必须是布尔类型(true 和 false):
iex> true and 42
42
iex> false or true
true
iex> not false
true
iex> 42 and true
** (ArgumentError) argument error: 42
iex> not 42
** (ArgumentError) argument error
比较运算符 :
==
,!=
,===
,!==
,<=
,>=
,<
和>
iex> 1 > 2
false
iex> 1 != 2
true
iex> 2 == 2
true
iex> 2 <= 3
true
iex> name = "Sean"
iex> "Hello #{name}"
"Hello Sean"
iex> "Hello " <> "world!"
"Hello world!"
列表(list)、元组(tuple)、关键字列表(keyword list)、映射(map)。
iex> [3.14, :pie, "Apple"]
[3.14, :pie, "Apple"]
iex> list = [3.14, :pie, "Apple"]
iex> [3.14, :pie, "Apple"]
iex> ["π" | list] # 列表的开头添加元素
["π", 3.14, :pie, "Apple"]
iex> list ++ ["Cherry"] # 列表的尾部添加元素/列表拼接
[3.14, :pie, "Apple", "Cherry"]
iex> hd [3.14, :pie, "Apple"] # 获取列表的头部元素
3.14
iex> tl [3.14, :pie, "Apple"] # 获取列表的尾部元素
[:pie, "Apple"]
iex> {3.14, :pie, "Apple"}
{3.14, :pie, "Apple"}
iex> [foo: "bar", hello: "world"]
[foo: "bar", hello: "world"]
iex> [{:foo, "bar"}, {:hello, "world"}]
[foo: "bar", hello: "world"]
关键字列表非常重要,它有以下的特性:
因为这些原因,关键字列表最常见的用法是作为参数传递给函数。
Elixir 的映射(maps)是键值对结构的第一选择,和关键字列表(keywords)不同,映射允许任意类型的数据作为键,而且数据并不严格排序。 你可以使用 %{} 来定义映射:
iex> map = %{:foo => "bar", "hello" => :world}
%{:foo => "bar", "hello" => :world}
iex> map[:foo]
"bar"
iex> map["hello"]
:world
模式匹配是 Elixir 很强大的特性,它允许我们匹配简单值、数据结构、甚至函数。
# 匹配元组
iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
iex> a
:hello
iex> b
"world"
# 匹配列表
iex> [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex> a
1
# 匹配列表的头部元素
iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
pin 操作符,就是用已经绑定的值去匹配,而不是重新绑定一个新值。
iex> {x, ^x} = {2, 1}
{2, 1}
iex> x
2
# 使用下划线_忽略匹配的值
iex> [head | _] = [1, 2, 3]
[1, 2, 3]
iex> head
1
case, cond, and if
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
"This clause will match and bind x to 2 in this clause"
# 还可以使用when指定额外的条件
iex> case {1, 2, 3} do
{1, x, 3} when x > 0 ->
"Will match"
_ ->
"Would match, if guard condition were not satisfied"
end
"Will match"
当我们需要匹配条件而不是值的时候,可以使用 cond,这和其他语言的 else if 或者 elsif 相似
iex> cond do
2 + 2 == 5 ->
"This will not be true"
2 * 2 == 3 ->
"Nor this"
1 + 1 == 2 ->
"But this will"
end
"But this will"
# 如果所有的条件都返回nil或false,则会引发一个错误(CondClauseError)。因此,需要添加一个final条件,等于true,它将始终匹配:
iex> cond do
2 + 2 == 5 ->
"This is never true"
2 * 2 == 3 ->
"Nor this"
true ->
"This is always true (equivalent to else)"
end
"This is always true (equivalent to else)"
iex> if true do
"This works!"
end
"This works!"
iex> unless true do
"This will never be seen"
end
nil
# if...else...
iex> if nil do
"This won't be seen"
else
"This will"
end
"This will"
# 关于Elixir中变量的作用域:如果在if、case和类似的构造中声明或更改了任何变量,则声明和更改将只在构造中可见。
iex> x = 1
1
if true do
x = x + 1
end
2
iex> x
1
# 如果要更改值,则必须从if返回值:
iex> x = 1
1
iex> x = if true do
x + 1
else
x
end
2
使用 fn 和 end 关键字来定义匿名函数,在这两者之间,可以定义任意数量的参数和函数体,它们用 -> 分隔开。
iex> sum = fn (a, b) -> a + b end
iex> sum.(2, 3)
5
# 可以使用 & 语法来简化匿名函数的定义:
iex> sum = &(&1 + &2)
iex> sum.(2, 3)
5
匿名函数去引用外部的变量,这通常被称为闭包。
iex> double = fn a -> add.(a, a) end
#Function<6.71889879/1 in :erl_eval.expr/5>
double.(2)
4
闭包与守卫
iex> f = fn
x, y when x > 0 -> x + y
x, y -> x * y
end
iex> f.(1, 3)
4
iex> f.(-1, 3)
-3
命名函数是通过 def 关键字定义在某个模块中
defmodule Greeter do
def hello(name) do
"Hello, " <> name
end
end
iex> Greeter.hello("Sean")
"Hello, Sean"
# 简写为一行:
defmodule Greeter do
def hello(name), do: "Hello, " <> name
end
# 私有函数
defmodule Greeter do
def hello(name), do: phrase <> name
defp phrase, do: "Hello, " # 使用defp来定义私有函数
end
函数的默认参数:使用
\\
来定义默认参数
defmodule Greeter do
def hello(name, language_code \\ "en") do
phrase(language_code) <> name
end
defp phrase("en"), do: "Hello, "
defp phrase("es"), do: "Hola, "
end
Elixir 提供了 Enum 和 Stream 两个模块,用于处理集合。
Enum 模块提供了对集合的常用操作,如 map、filter、reduce、sort、chunk、join、into 等。
iex> Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.map(%{1 => 2, 3 => 4}, fn {k, v} -> k * v end)
[2, 12]
作为Enum的替代品,Elixir提供了支持懒惰操作的Stream模块
iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum()
7500000000
流文件操作
iex> stream = File.stream!("path/to/file")
%File.Stream{
line_or_bytes: :line,
modes: [:raw, :read_ahead, :binary],
path: "path/to/file",
raw: true
}
Enum.take(stream, 10)
# 上面的例子将提取所选文件的前10行。这意味着流对于处理大型文件甚至是网络资源等慢速资源非常有用。