doc: update docs/elixir.md #587

This commit is contained in:
jaywcjlove 2024-04-02 16:09:00 +08:00
parent 8d60181b96
commit 3fdfa19b74

View File

@ -6,20 +6,22 @@ Elixir 备忘清单
入门 入门
------ ------
### 安装Elixir ### 安装 Elixir
<!--rehype:wrap-class=row-span-2-->
> 每个操作系统的安装说明可以在 elixir-lang.org 网站上 [Installing Elixir](http://elixir-lang.org/install.html) 部分找到。 Elixir 自带了 `iex` 这样一个交互 shell可以随时计算 Elixir 表达式的值,运行`iex`命令,继续输入几个简单的表达式试试:
> Elixir 自带了`iex`这样一个交互 shell可以随时计算 Elixir 表达式的值,运行`iex`命令,继续输入几个简单的表达式试试:
```shell ```shell
iex 2+3 iex 2+3
5 5
iex 2+3 == 5 iex 2+3 == 5
true true
iex String.length("The quick brown fox jumps over the lazy dog") iex String.length("快速的狐狸跳过了懒惰的狗")
43 43
``` ```
每个操作系统的文档可以在[官网](https://elixir-lang.org)网站上 [Installing Elixir](http://elixir-lang.org/install.html) 部分找到
### hello.exs ### hello.exs
```elixir ```elixir
@ -33,21 +35,128 @@ $ elixir hello.exs
``` ```
### 基本类型 ### 基本类型
> <!--rehype:wrap-class=row-span-3-->
> Elixir 支持多种基本类型:整数、浮点、布尔值、原子和字符串。其他数据类型,如列表和元组
Elixir 支持多种基本类型:整数、浮点、布尔值、原子和字符串。其他数据类型,如列表和元组
```elixir ```elixir
iex> 1 # integer # integer 整数
iex> 0x1F # integer支持二进制、八进制和十六进制的整数 iex> 1
iex> 1.0 # float # integer支持2进制、8进制和16进制的整数
iex> true # boolean iex> 0x1F
iex> :atom # atom / symbol # float
iex> "elixir" # string iex> 1.0
iex> [1, 2, 3] # list # boolean
iex> {1, 2, 3} # tuple iex> true
# atom / symbol
iex> :atom
# string
iex> "elixir"
# list
iex> [1, 2, 3]
# tuple
iex> {1, 2, 3}
```
### 注释
```elixir
# 这是一个单行注释
```
### 字符串插值与拼接
```elixir
iex> name = "Sean"
iex> "Hello #{name}"
"Hello Sean"
iex> "Hello " <> "world!"
"Hello world!"
```
### 变量和模式匹配
```elixir
x = 1
# => x 现在等于 1
{a, b} = {1, 2}
# => a 等于 1b 等于 2
```
在 Elixir 中,使用 `=` 来进行赋值操作,但实际上是模式匹配。左边是模式,右边是值
### 原子Atoms
```elixir
:ok
```
原子是常量,它们的名称就是它们的值
### 列表Lists
```elixir
list = [1, 2, 3]
```
### 元组Tuples
```elixir
tuple = {:ok, "value"}
```
### 函数定义
```elixir
defmodule MyModule do
def my_function(parameter) do
# 函数体
end
end
```
### 匿名函数
```elixir
add = fn a, b -> a + b end
```
### 控制结构
<!--rehype:wrap-class=row-span-2-->
`if/else`
```elixir
if x > 0 do
"Positive"
else
"Non-positive"
end
```
`case`
```elixir
case {1, 2} do
{1, x} -> "Matched #{x}"
_ -> "Not matched"
end
```
`cond`
```elixir
cond do
x > 2 -> "Greater than 2"
x == 2 -> "Equal to 2"
true -> "Less than 2"
end
``` ```
### 基本算术 ### 基本算术
<!--rehype:wrap-class=row-span-4-->
```elixir ```elixir
iex> 1 + 2 iex> 1 + 2
@ -58,18 +167,23 @@ iex> 10 / 2
5.0 5.0
``` ```
> 运算符`/`总是返回一个float。如果你想做整数除法或得到除法余数你可以调用div和rem函数: 运算符`/`总是返回一个 float。如果你想做整数除法或得到除法余数你可以调用 div rem 函数:
```elixir ```elixir
iex> div(10, 2) iex> div(10, 2)
5 5
iex> div 10, 2 # Elixir允许在调用需要一个或多个参数的函数时删除括号 ```
允许在调用需要一个或多个参数的函数时删除括号
```elixir
iex> div 10, 2
5 5
iex> rem 10, 3 iex> rem 10, 3
1 1
``` ```
> 可以调用round函数来获取与给定浮点数最接近的整数或者调用trunc函数来获取浮点数的整数部分 可以调用 round 函数来获取与给定浮点数最接近的整数,或者调用 trunc 函数来获取浮点数的整数部分
```elixir ```elixir
iex> round(3.58) iex> round(3.58)
@ -78,7 +192,7 @@ iex> trunc(3.58)
3 3
``` ```
> 可以使用is_integer、is_float或is_number分别检查参数是否为integer、float或number类型 可以使用 is_integer、is_float is_number 分别检查参数是否为 integer、float number 类型
```elixir ```elixir
iex> is_integer(1) iex> is_integer(1)
@ -90,8 +204,9 @@ false
``` ```
### 布尔算术 ### 布尔算术
> <!--rehype:wrap-class=row-span-4-->
> Elixir 提供了 `||``&&``!` 布尔操作符,它们支持任何类型的操作:
Elixir 提供了 `||``&&``!` 布尔操作符,它们支持任何类型的操作:
```elixir ```elixir
iex> -20 || true iex> -20 || true
@ -110,7 +225,7 @@ iex> !false
true true
``` ```
> 还有三个操作符and、or、not它们的第一个参数**必须是布尔类型**true 和 false: 还有三个操作符and、or、not它们的第一个参数**必须是布尔类型**true 和 false:
```elixir ```elixir
iex> true and 42 iex> true and 42
@ -125,9 +240,25 @@ iex> not 42
** (ArgumentError) argument error ** (ArgumentError) argument error
``` ```
### 模块和函数导入
```elixir
import List, only: [duplicate: 2]
```
### 管道操作符
```elixir
result = data
|> process1()
|> process2()
```
`|>` 用于链式调用函数,将前一个函数的结果作为下一个函数的第一个参数
### 比较运算符 ### 比较运算符
>
> 比较运算符 `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<``>` 比较运算符 `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<``>`
```elixir ```elixir
iex> 1 > 2 iex> 1 > 2
@ -140,23 +271,14 @@ iex> 2 <= 3
true true
``` ```
### 字符串插值与拼接
```elixir
iex> name = "Sean"
iex> "Hello #{name}"
"Hello Sean"
iex> "Hello " <> "world!"
"Hello world!"
```
集合 集合
------ ------
> >
> 列表list、元组tuple、关键字列表keyword list、映射map > 列表list、元组tuple、关键字列表keyword list、映射map
> >
### 列表List ### 列表List
<!--rehype:wrap-class=row-span-2-->
```elixir ```elixir
iex> [3.14, :pie, "Apple"] iex> [3.14, :pie, "Apple"]
@ -164,14 +286,34 @@ iex> [3.14, :pie, "Apple"]
iex> list = [3.14, :pie, "Apple"] iex> list = [3.14, :pie, "Apple"]
iex> [3.14, :pie, "Apple"] iex> [3.14, :pie, "Apple"]
iex> ["π" | list] # 列表的开头添加元素 ```
列表的开头添加元素
```elixir
iex> ["π" | list]
["π", 3.14, :pie, "Apple"] ["π", 3.14, :pie, "Apple"]
iex> list ++ ["Cherry"] # 列表的尾部添加元素/列表拼接 ```
列表的尾部添加元素/列表拼接
```elixir
iex> list ++ ["Cherry"]
[3.14, :pie, "Apple", "Cherry"] [3.14, :pie, "Apple", "Cherry"]
iex> hd [3.14, :pie, "Apple"] # 获取列表的头部元素 ```
获取列表的头部元素
```elixir
iex> hd [3.14, :pie, "Apple"]
3.14 3.14
iex> tl [3.14, :pie, "Apple"] # 获取列表的尾部元素 ```
获取列表的尾部元素
```elixir
iex> tl [3.14, :pie, "Apple"]
[:pie, "Apple"] [:pie, "Apple"]
``` ```
@ -191,17 +333,17 @@ iex> [{:foo, "bar"}, {:hello, "world"}]
[foo: "bar", hello: "world"] [foo: "bar", hello: "world"]
``` ```
> 关键字列表非常重要,它有以下的特性: 关键字列表非常重要,它有以下的特性:
- 键key都是原子atom - 键key都是原子atom
- 键key是有序的定义后顺序不会改变 - 键key是有序的定义后顺序不会改变
- 键key不必是唯一的 - 键key不必是唯一的
> 因为这些原因,关键字列表最常见的用法是作为参数传递给函数 因为这些原因,常见的用法是作为参数传递给函数
### 映射Map ### 映射Map
> Elixir 的映射maps是键值对结构的第一选择和关键字列表keywords不同映射允许任意类型的数据作为键而且数据并不严格排序。 你可以使用 %{} 来定义映射: Elixir 的映射maps是键值对结构的第一选择和关键字列表keywords不同映射允许任意类型的数据作为键而且数据并不严格排序。 你可以使用 %{} 来定义映射:
```elixir ```elixir
iex> map = %{:foo => "bar", "hello" => :world} iex> map = %{:foo => "bar", "hello" => :world}
@ -214,26 +356,34 @@ iex> map["hello"]
模式匹配 模式匹配
------ ------
> >
> 模式匹配是 Elixir 很强大的特性,它允许我们匹配简单值、数据结构、甚至函数。 > 模式匹配是 Elixir 很强大的特性,它允许我们匹配简单值、数据结构、甚至函数。
> >
### 匹配操作符
### 匹配元组
```elixir ```elixir
# 匹配元组
iex> {a, b, c} = {:hello, "world", 42} iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42} {:hello, "world", 42}
iex> a iex> a
:hello :hello
iex> b iex> b
"world" "world"
```
# 匹配列表 ### 匹配列表
```
iex> [a, b, c] = [1, 2, 3] iex> [a, b, c] = [1, 2, 3]
[1, 2, 3] [1, 2, 3]
iex> a iex> a
1 1
# 匹配列表的头部元素 ```
### 匹配列表的头部元素
```
iex> [head | tail] = [1, 2, 3] iex> [head | tail] = [1, 2, 3]
[1, 2, 3] [1, 2, 3]
iex> head iex> head
@ -242,17 +392,20 @@ iex> tail
[2, 3] [2, 3]
``` ```
### Pin操作符 ### Pin 操作符
> pin 操作符,就是用已经绑定的值去匹配,而不是重新绑定一个新值。 pin 操作符,就是用已经绑定的值去匹配,而不是重新绑定一个新值。
```elixir ```elixir
iex> {x, ^x} = {2, 1} iex> {x, ^x} = {2, 1}
{2, 1} {2, 1}
iex> x iex> x
2 2
```
# 使用下划线_忽略匹配的值 ### 使用下划线 `_` 忽略匹配的值
```elixir
iex> [head | _] = [1, 2, 3] iex> [head | _] = [1, 2, 3]
[1, 2, 3] [1, 2, 3]
iex> head iex> head
@ -261,37 +414,89 @@ iex> head
控制语句 控制语句
------ ------
>
> case, cond, and if ### if/else/end
>
```elixir
if condition do
# 条件成立时执行的代码
else
# 条件不成立时执行的代码
end
```
### case/end
```elixir
case expression do
pattern1 -> # 匹配 pattern1 时执行的代码
pattern2 -> # 匹配 pattern2 时执行的代码
_ -> # 其他情况执行的代码
end
```
### cond/end
```elixir
cond do
condition1 -> # 条件1成立时执行的代码
condition2 -> # 条件2成立时执行的代码
true -> # 如果没有任何条件成立,执行这里的代码
end
```
### unless/do/end
```elixir
unless condition do
# 条件为假时执行的代码
end
```
### try/rescue/end
```elixir
try do
# 可能会引发异常的代码
rescue
pattern1 -> # 匹配 pattern1 的异常处理代码
pattern2 -> # 匹配 pattern2 的异常处理代码
_ -> # 其他异常处理代码
end
```
### case ### case
> <!--rehype:wrap-class=row-span-2-->
> case允许我们将一个值与许多模式进行比较直到找到匹配的模式
允许将一个值与许多模式进行比较,直到找到匹配的模式:
```elixir ```elixir
iex> case {1, 2, 3} do iex> case {1, 2, 3} do
{4, 5, 6} -> {4, 5, 6} ->
"This clause won't match" "This clause won't match"
{1, x, 3} -> {1, x, 3} ->
"This clause will match and bind x to 2 in this clause" "该子句将匹配并绑定 x 到该子句中的 2"
_ -> _ ->
"This clause would match any value" "This clause would match any value"
end end
"This clause will match and bind x to 2 in this clause" "该子句将匹配并绑定 x 到该子句中的 2"
```
# 还可以使用when指定额外的条件 还可以使用when指定额外的条件
```elixir
iex> case {1, 2, 3} do iex> case {1, 2, 3} do
{1, x, 3} when x > 0 -> {1, x, 3} when x > 0 ->
"Will match" "Will match"
_ -> _ ->
"Would match, if guard condition were not satisfied" "如果不满足保护条件,将匹配"
end end
"Will match" "Will match"
``` ```
### cond ### cond
> 当我们需要匹配条件而不是值的时候,可以使用 cond这和其他语言的 else if 或者 elsif 相似 当我们需要根据条件进行匹配而不是值时,类似于其他语言的 `else if``elsif`,可以使用 `cond` 控制结构。
```elixir ```elixir
iex> cond do iex> cond do
@ -303,41 +508,27 @@ iex> cond do
"But this will" "But this will"
end end
"But this will" "But this will"
```
# 如果所有的条件都返回nil或false则会引发一个错误CondClauseError。因此需要添加一个final条件等于true它将始终匹配 如果所有的条件都返回 `nil``false`则会引发一个错误CondClauseError。因此需要添加一个 `final` 条件,等于 `true`,它将始终匹配:
```elixir
iex> cond do iex> cond do
2 + 2 == 5 -> 2 + 2 == 5 ->
"This is never true" "This is never true"
2 * 2 == 3 -> 2 * 2 == 3 ->
"Nor this" "Nor this"
true -> true ->
"This is always true (equivalent to else)" "这始终为真(等同于 else"
end end
"This is always true (equivalent to else)" "这始终为真(等同于 else"
``` ```
### if/unless ### 变量的作用域
如果在if、case和类似的构造中声明或更改了任何变量则声明和更改将只在构造中可见。
```elixir ```elixir
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 iex> x = 1
1 1
if true do if true do
@ -346,8 +537,11 @@ end
2 2
iex> x iex> x
1 1
```
# 如果要更改值则必须从if返回值 如果要更改值则必须从if返回值
```elixir
iex> x = 1 iex> x = 1
1 1
iex> x = if true do iex> x = if true do