Kernel

核心

提供Elixir导入到您的环境中的默认宏和函数。

这些宏和函数可以跳过或通过import/2宏。例如,如果您想告诉Elixir不要导入if/2宏,您可以:

import Kernel, except: [if: 2]

Elixir也有特殊的形式,总是进口,不能跳过。这些描述在Kernel.SpecialForms

本模块中描述的一些功能由Elixir编译器内联到erlang模块中的Erlang对应内容中。 这些函数在Erlang-land中称为BIF(内置内部函数),并且它们展现出有趣的属性,因为它们中的一些被允许在守卫中,另一些被用于编译器优化。

捕捉功能时,大部分内联函数都可以看到效果:

iex> &Kernel.is_atom/1 &:erlang.is_atom/1

这些函数将在文档中明确标记为“由编译器内联”。

摘要

功能

!value

Boolean not

left != right

如果这两项不相等,返回true

left !== right

如果这两项不完全相等,返回true

left && right

提供一个短路运算符,仅当第一个表达式评估为true(即既不是nil也不是false)时才评估并返回第二个表达式。否则返回第一个表达式

left * right

算术乘法

+值

算术一元加

left + right

算术加法

left ++ right

列出一个适当的列表和一个术语,并返回一个列表。

-value

算术一元减

left - right

算术减法

left -- right

移除右侧每个项目的左列表中项的第一个匹配项。

first..last

返回具有指定值的范围。firstlast整数

left / right

算术划分

left < right

如果左小于右,返回true

left <= right

如果左小于或等于右,返回true

left <> right

连接两个二进制文件

left == right

如果两项相等,返回true

left === right

如果这两项完全相等,返回true

left =~ right

将左侧的术语与右侧的正则表达式或字符串匹配。

left > right

如果左多于右,返回true

left >= right

如果左大于或等于右,返回true

@expr

读取和写入当前模块的属性。

abs(number)

返回整数或浮点数,该整数或浮点数是number

alias!(alias)

当在引用中使用时,标记指定的别名不应该卫生。这意味着在展开宏时将展开别名。

left and right

Boolean and

apply(fun, args)

调用给定的fun与参数列表args

apply(module, fun, args)

用参数args列表从模块中调用给定的fun

binary_part(binary, start, length)

从长度开始提取二进制文件的一部分。 二进制文件是零索引的

binding(context \ nil)

将给定上下文的绑定作为关键字列表返回。

bit_size(bitstring)

返回一个整数,其大小是bitstring的大小

byte_size(bitstring)

返回包含bitstring所需的字节数

def(call, expr \ nil)

定义具有给定名称和正文的函数。

defdelegate(funs, opts)

定义委托给另一个模块的函数。

defexception(fields)

定义异常

defimpl(name, opts, do_block \ [])

定义给定协议的实现。

defmacro(call, expr \ nil)

定义具有给定名称和正文的宏。

defmacrop(call, expr \ nil)

定义具有给定名称和正文的私有宏。

defmodule(alias, do_block)

用给定的内容定义按名称指定的模块。

defoverridable(keywords_or_behaviour)

使当前模块中的给定函数可重写。

defp(call, expr \ nil)

定义具有给定名称和正文的私有函数。

defprotocol(name, do_block)

定义协议

defstruct(fields)

定义结构

destructure(left, right)

构造两个列表,将右边的每个项分配给左侧的匹配项。

div(dividend, divisor)

执行整数除法

elem(tuple, index)

获取元组中从零开始索引处的元素

exit(reason)

在给定的原因下停止调用进程的执行。

function_exported?(module, function, arity)

如果模块已加载并且包含具有给定元素的公共函数,则返回true,否则返回false

get_and_update_in(路径,函数)

获取值并通过给定值更新嵌套的数据结构 path

get_and_update_in(数据,键,函数)

获取一个值并更新嵌套结构。

get_in(数据,键)

获取嵌套结构的值。

hd(list)

返回列表的头部。如果列表为空,则引发ArgumentError

if(condition, clauses)

提供一个if/2

左转右

检查左侧的元素是否为右侧集合的成员。

inspect(term, opts \ [])

根据Inspect协议。第二个参数是带有控制检查选项的关键字列表。

is_atom(term)

如果term是一个原子,则返回true; 否则返回false

is_binary(term)

如果term是二进制,则返回true; 否则返回false

is_bitstring(term)

如果term是一个位串(包括二进制),则返回true; 否则返回false

is_boolean(term)

如果term是原子true或原子false,则返回true(即,布尔值); 否则返回false

is_float(term)

如果term是一个浮点数,则返回true; 否则返回false

is_function(term)

回报true如果term是一个函数,否则返回false

is_function(term, arity)

如果term是一个可以用参数数量来应用的函数,则返回true; 否则返回false

is_integer(term)

如果term是一个整数,则返回true; 否则返回false

is_list(term)

如果term是包含零个或多个元素的列表,则返回true; 否则返回false

is_map(term)

如果term是map,则返回true; 否则返回false

is_nil(term)

如果term是零,则返回true,否则返回false

is_number(term)

如果term是整数或浮点数,则返回true; 否则返回false

is_pid(term)

如果term是一个PID(进程标识符),则返回true; 否则返回false

is_port(term)

如果term是一个端口标识符,则返回true; 否则返回false

is_reference(term)

如果term是引用,则返回true; 否则返回false

is_tuple(term)

如果term是一个元组,则返回true; 否则返回false

length(list)

返回list

macro_exported?(module, macro, arity)

如果模块已加载并且包含具有给定元素的公共宏,则返回true,否则返回false

make_ref()

返回几乎唯一的引用。

map_size(map)

返回地图的大小。

match?(pattern, expr)

一个方便的宏,用于检查右侧(表达式)是否匹配左侧(一个模式)

max(first, second)

根据Erlang的项排序返回两个给定项中的最大项

min(first, second)

根据Erlang项的顺序返回两个给定项中最小的一个

node()

返回表示本地节点名称的原子。如果节点不活动,则返回:nonode@nohost

node(arg)

返回给定参数所在的节点。参数可以是PID、引用或端口。如果本地节点没有活动,:nonode@nohost返回

非价值

布尔非

左或右

布尔或

pop_in(path)

从嵌套结构中弹出密钥path

pop_in(data, keys)

从给定的嵌套结构中弹出密钥。

put_elem(tuple, index, value)

在元组中插入给定的从零开始的索引值

put_in(path, value)

通过给定的path

put_in(data, keys, value)

将值放入嵌套结构中。

raise(message)

引发异常

raise(exception, attributes)

引发异常

rem(dividend, divisor)

计算整数除法的剩余部分。

reraise(message, stacktrace)

引发保存以前堆栈跟踪的异常。

reraise(exception, attributes, stacktrace)

引发保存以前堆栈跟踪的异常。

round(number)

将数字舍入到最近的整数。

self()

返回调用进程的PID(进程标识符)

send(dest, message)

向给定的dest并返回消息

sigil_C(term, modifiers)

处理信号~C

sigil_D(date, modifiers)

处理~D日期的印记

sigil_N(date, modifiers)

处理~N单纯时间的印记

sigil_R(term, modifiers)

处理信号~R

sigil_S(term, modifiers)

处理信号~S

sigil_T(date, modifiers)

处理信号~T几次

sigil_W(term, modifiers)

处理信号~W

sigil_c(term, modifiers)

处理信号~c

sigil_r(term, modifiers)

处理信号~r

sigil_s(term, modifiers)

处理信号~s

sigil_w(term, modifiers)

处理信号~w

spawn(fun)

生成给定函数并返回其PID。

spawn(module, fun, args)

生成给定函数fun从给定的module把它传递给args并返回它的PID

spawn_link(fun)

生成给定的函数,将其链接到当前进程,并返回其PID。

spawn_link(module, fun, args)

生成给定函数fun从给定的module把它传递给args,将其链接到当前进程,并返回其PID。

spawn_monitor(fun)

生成给定的函数,监视它,并返回它的PID和监视引用。

spawn_monitor(module, fun, args)

生成传递给定args的给定模块和函数,监视它,并返回它的PID和监视引用。

struct(struct, fields \ [])

创建和更新结构

struct!(struct, fields \ [])

类似于struct/2但检查关键有效性

throw(term)

来自函数的非本地返回

返回列表的尾部。提高ArgumentError如果列表为空

返回列表的尾部。如果列表为空,则引发ArgumentError

to_charlist(term)

根据List.Chars协议将给定的术语转换为charlist

to_string(term)

根据String.Chars协议将参数转换为字符串

trunc(number)

返回 number整数部分

tuple_size(tuple)

返回元组的大小

unless(condition, clauses)

提供一个unless

update_in(path, fun)

更新嵌套结构中的键

update_in(data, keys, fun)

在当前上下文中使用给定模块。

use(module, opts \ [])

在当前上下文中使用给定的模块

var!(var, context \ nil)

在引用中使用时,标记给定的变量不应卫生

left |> right

功能

left || right

提供一个短路运算符,仅当第一个表达式不计算为true(即,它是nilfalse)时才评估并返回第二个表达式。否则返回第一个表达式

功能

!值(宏)

不是布尔值。

接收任何参数(不只是布尔值)并返回true参数为falsenil; 否则返回false

警卫条款不允许。

例子

iex> !Enum.empty?([]) false iex> !List.first([]) true

left != right

term != term :: boolean

如果两个项目不相等则返回true

该运算符认为1和1.0是相等的。为了比较比较,请改用!==

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 != 2 true iex> 1 != 1.0 false

left !== right

term !== term :: boolean

如果两个项目不完全相等则返回true

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 !== 2 true iex> 1 !== 1.0 true

left && right (macro)

提供一个短路运算符,仅当第一个表达式的值为真时(即,既不为零也不为假)评估并返回第二个表达式。 否则返回第一个表达式。

警卫条款不允许。

例子

iex> Enum.empty?([]) && Enum.empty?([]) true iex> List.first([]) && true nil iex> Enum.empty?([]) && List.first([1]) 1 iex> false && throw(:bad) false

请注意,与and/2此不同,此运算符接受任何表达式作为第一个参数,而不仅仅是布尔值。

left * right

float * integer :: float

整数* float :: float

float * float :: float

integer * integer :: integer

算术乘法。

允许在警卫测试。由编译器内联。

例子

iex> 1 * 2 2

+值

+value :: value when value: number

算术一元加。

允许在警卫测试。由编译器内联。

例子

iex> +1 1

向左+向右

float + integer :: float

integer + float :: float

float + float :: float

integer + integer :: integer

算术加法。

允许在警卫测试。由编译器内联。

例子

iex> 1 + 2 3

左++右

list ++ term :: maybe_improper_list

连接一个正确的列表和一个术语,返回一个列表。

a ++ b的复杂度与长度(a)成正比,因此避免重复附加到任意长度的列表,例如 列表++ [item]。 相反,请考虑通过[item |预先考虑 休息]然后倒车。

如果right操作数不是一个正确的列表,它将返回一个不正确的列表。如果left操作数不是一个适当的列表,它会引发ArgumentError

由编译器内联。

例子

iex> [1] ++ [2, 3] [1, 2, 3] iex> 'foo' ++ 'bar' 'foobar' # returns an improper list iex> [1] ++ 2 [1 | 2] # returns a proper list iex> [1] ++ [2] [1, 2] # improper list on the right will return an improper list iex> [1] ++ [2 | 3] [1, 2 | 3]

-值

-float :: float

-neg_integer :: pos_integer

-pos_integer :: neg_integer

-0 :: 0

算术一元减号。

允许在警卫测试。由编译器内联。

例子

iex> -2 -2

left - right

float - integer :: float

integer - float :: float

float - float :: float

integer - integer :: integer

算术减法。

允许在警卫测试。由编译器内联。

例子

iex> 1 - 2 -1

left -- right

list -- list :: list

删除右侧每个项目左侧列表中第一次出现的项目。

在复杂a -- b成正比length(a) * length(b),这意味着它会很慢,如果双方ab很长的列表。在这种情况下,请考虑将每个列表转换为MapSet并使用MapSet.difference/2

由编译器内联。

例子

iex> [1, 2, 3] -- [1, 2] [3] iex> [1, 2, 3, 2, 1] -- [1, 2, 2] [3, 1]

first..last(宏)

返回具有指定firstlast整数的范围。

如果最后一个比第一个大,则范围将从第一个到最后一个增加。如果第一个比上一个大,则范围将从第一个到最后一个减少。如果第一个等于最后一个,则范围将包含一个元素,它是数字本身。

例子

iex> 0 in 1..3 false iex> 1 in 1..3 true iex> 2 in 1..3 true iex> 3 in 1..3 true

left / right

number / number :: float

算术分割。

结果总是一个浮动。使用div/2rem/2如果你想要一个整数除法或余数。

如果right为0或0.0,则引发ArithmeticError。

允许在警卫测试。由编译器内联。

例子

1 / 2 #=> 0.5 -3.0 / 2.0 #=> -1.5 5 / 1 #=> 5.0 7 / 0 #=> **(ArithmeticError)算术表达式中的错误参数

left < right

term < term :: boolean

如果left小于right,则返回true

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 < 2 true

left <= right

term <= term :: boolean

如果left小于或等于right,则返回true

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 <= 2 true

left <> right (macro)

连接两个二进制文件。

例子

iex> "foo" <> "bar" "foobar"

<>只要第一部分是文字二进制,操作符也可用于模式匹配(和保护子句):

iex> "foo" <> x = "foobar" iex> x "bar"

x <> "bar" = "foobar"会导致一个CompileError例外。

left == right

term == term :: boolean

如果两个项目相等则返回true

该运算符认为1和1.0是相等的。对于更严格的语义,请改用===

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 == 2 false iex> 1 == 1.0 true

left === right

term === term :: boolean

如果两个项目完全相等则返回true

如果这些项目具有相同的值并且属于同一类型,则只会将其视为完全相同。例如,1 == 1.0返回true,但由于它们是不同的类型,所以1 === 1.0返回false。

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 === 2 false iex> 1 === 1.0 false

left =~ right

String.t =~ String.t | Regex.t :: boolean

匹配右侧的术语与右侧的正则表达式或字符串。

如果left匹配正确(如果它是正则表达式)或包含right(如果它是一个字符串),则返回true。

例子

iex> "abcd" =~ ~r/c(d)/ true iex> "abcd" =~ ~r/e/ false iex> "abcd" =~ "bc" true iex> "abcd" =~ "ad" false iex> "abcd" =~ "" true

left > right

term> term :: boolean

如果left超过正确值,则返回true。

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 > 2 false

left >= right

term> = term :: boolean

如果left大于或等于right,则返回true

Elixir中的所有术语都可以相互比较。

允许在警卫测试。由编译器内联。

例子

iex> 1 >= 2 false

@expr(宏)

读取和写入当前模块的属性。

属性的规范示例注释了模块实现OTP行为的方式,例如GenServer

defmodule MyServer do @behaviour GenServer # ... callbacks ... end

默认情况下,Elixir支持Erlang支持的所有模块属性,但也可以使用自定义属性:

defmodule MyServer do @my_data 13 IO.inspect @my_data #=> 13 end

与Erlang不同,这些属性默认不存储在模块中,因为在Elixir中通常使用自定义属性来存储在编译时可用的临时数据。通过使用自定义属性可以配置为更接近Erlang Module.register_attribute/3

最后,请注意,属性也可以在函数内读取:

defmodule MyServer do @my_data 11 def first_data, do: @my_data @my_data 13 def second_data, do: @my_data end MyServer.first_data #=> 11 MyServer.second_data #=> 13

重要的是要注意,读取属性需要获取其当前值的快照。换句话说,该值是在编译时读取的,而不是在运行时读取的。检查Module模块是否有其他功能来操作模块属性。

ABS(数)

abs(number) :: number

返回一个整数或浮点数,它是算术绝对值number

允许在警卫测试。由编译器内联。

例子

iex> abs(-3.33) 3.33 iex> abs(-3) 3

alias!(alias) (macro)

在引用中使用时,标记给定的别名不应卫生。这意味着当扩展宏时别名将被扩展。

查看Kernel.SpecialForms.quote / 2了解更多信息

left and right (macro)

布尔和。

如果第一个参数是false,则返回false; 否则,返回第二个参数。

由于短路,只需要第一个参数为布尔值。如果第一个参数不是布尔值,则会引发异常ArgumentError

允许在警卫测试。

例子

iex> true and false false iex> true and "yay!" "yay!"

apply(fun, args)

apply((... -> any), [any]) :: any

fun用参数列表调用给定的参数args

由编译器内联。

例子

iex> apply(fn x -> x * 2 end, [2]) 4

apply(module, fun, args)

apply(module, atom, [any]) :: any

funmodule参数列表中调用给定args

由编译器内联。

例子

iex> apply(Enum, :reverse, [[1, 2, 3]]) [3, 2, 1]

binary_part(binary, start, length)

binary_part(binary, non_neg_integer, integer) :: binary

start长度开始提取二进制文件的部分length。二进制文件是零索引的。

如果以任何方式在二进制外引用startlength引用,则会引发异常ArgumentError

允许在警卫测试。由编译器内联。

例子

iex> binary_part("foo", 1, 2) "oo"

length可以使用负数来提取字节前面的字节start

iex> binary_part("Hello", 5, -3) "llo"

绑定(context \ nil)(宏)

将给定上下文的绑定作为关键字列表返回。

在返回的结果中,键是变量名,值是相应的变量值。

如果给定contextnil(默认情况下是),则返回当前上下文的绑定。

例子

iex> x = 1 iex> binding() [x: 1] iex> x = 2 iex> binding() [x: 2] iex> binding(:foo) [] iex> var!(x, :foo) = 1 1 iex> binding(:foo) [x: 1]

bit_size(bitstring)

bit_size(bitstring) :: non_neg_integer

返回一个大小为整数的整数bitstring

允许在警卫测试。由编译器内联。

例子

iex> bit_size(<<433::16, 3::3>>) 19 iex> bit_size(<<1, 2, 3>>) 24

byte_size(比特串)

byte_size(bitstring) :: non_neg_integer

返回需要包含的字节数bitstring

也就是说,如果位数bitstring不能被8整除,则结果字节数将被四舍五入(超出)。此操作在不断的时间内发生。

允许在警卫测试。由编译器内联。

例子

iex> byte_size(<<433::16, 3::3>>) 3 iex> byte_size(<<1, 2, 3>>) 3

def(call,expr \ nil)(宏)

用给定的名称和正文定义一个函数。

例子

defmodule Foo do def bar, do: :baz end Foo.bar #=> :baz

需要参数的函数可以定义如下:

defmodule Foo do def sum(a, b) do a + b end end

在上面的例子中,sum/2定义了一个函数。这个函数接收两个参数并返回它们的总和。

默认参数

\\用于指定函数参数的默认值。例如:

defmodule MyMath do def multiply_by(number, factor \\ 2) do number * factor end end MyMath.multiply_by(4, 3) #=> 12 MyMath.multiply_by(4) #=> 8

编译器将其转换为具有不同arity的多个函数,这里Foo.multiply_by/1Foo.multiply_by/2表示带有默认值的参数的参数被传递或未传递的情况。

当使用默认参数定义函数以及多个显式声明的子句时,您必须编写一个声明默认值的函数头。例如:

defmodule MyString do def join(string1, string2 \\ nil, separator \\ " ") def join(string1, nil, _separator) do string1 end def join(string1, string2, separator) do string1 <> separator <> string2 end end

请注意,\\不能与匿名函数一起使用,因为它们只能有一个元素。

函数和变量名称

函数和变量名称具有以下语法:小写ASCII字母下划线,后跟任意数量的小写或大写ASCII字母数字下划线。可选地,它们可以以感叹号问号结束

对于变量,任何以下划线开头的标识符都应指示一个未使用的变量。例如:

def foo(bar) do [] end #=> warning: variable bar is unused def foo(_bar) do [] end #=> no warning def foo(_bar) do _bar end #=> warning: the underscored variable "_bar" is used after being set

rescue/catch/after

FunctionForms.try / 1的功能体支持救援,捕获和追踪。 以下两个功能是等同的:

def format(value) do try do format!(value) catch :exit, reason -> {:error, reason} end end def format(value) do format!(value) catch :exit, reason -> {:error, reason} end

defdelegate(funs, opts) (macro)

定义一个委托给另一个模块的函数。

使用定义的函数defdelegate/2是公共的,并且可以从它们定义的模块外部调用(例如,如果它们是使用定义的def/2)。当需要作为私人功能委托时,import/2应该使用。

授权只适用于功能; 不支持委派宏。

检查def/2命名和默认参数的规则。

选项

  • :to - 要发送到的模块。

  • :as- 调用中给出的目标的函数:to。该参数是可选的,并且默认为被委派的名称(funs)。

例子

defmodule MyList do defdelegate reverse(list), to: :lists defdelegate other_reverse(list), to: :lists, as: :reverse end MyList.reverse([1, 2, 3]) #=> [3, 2, 1] MyList.other_reverse([1, 2, 3]) #=> [3, 2, 1]

defexception(字段)(宏)

定义一个例外。

异常是由实现该Exception行为的模块支持的结构。该Exception行为需要执行两个功能:

  • exception/1- 接收给定的参数raise/2并返回异常结构。默认实现接受一组合并到结构中的关键字参数或一个字符串作为异常的消息。

  • message/1 - 接收到异常结构并且必须返回它的消息。最常见的例外有一个消息字段,默认情况下该消息字段由该函数访问。但是,如果某个异常没有消息字段,则必须明确实现此功能。

由于异常是结构,所支持的API defstruct/1也可以在defexception/1

提出例外

引发异常的最常见方式是raise/2

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

在许多情况下,传递期望值以raise / 2并在Exception.exception / 1回调中生成消息更方便:

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

上面的示例显示了定制异常消息的首选策略。

defimpl(name,opts,do_block \ [])(宏)

定义给定协议的实现。

请参阅defprotocol/2有关协议的更多信息和示例。

在一个实现中,协议的名称可以通过@protocol和当前目标访问@for

defmacro(call,expr \ nil)(宏)

用给定的名称和正文定义一个宏。

检查def/2命名和默认参数的规则。

例子

defmodule MyLogic do defmacro unless(expr, opts) do quote do if !unquote(expr), unquote(opts) end end end require MyLogic MyLogic.unless false do IO.puts "It works" end

defmacrop(call,expr \ nil)(宏)

用给定的名称和正文定义一个私有宏。

私有宏只能从定义它们的相同模块访问。

检查defmacro/2更多信息,并检查def/2有关命名和默认参数的规则。

defmodule(别名,do_block)(宏)

用给定内容定义由名称给出的模块。

这个宏定义了一个模块,其中给定alias的名称和给定的内容。它返回一个包含四个元素的元组:

  • 内容块的评价结果

  • 模块名称

  • 模块的二进制内容

  • 评估内容块的结果

例子

iex> defmodule Foo do ...> def bar, do: :baz ...> end iex> Foo.bar :baz

嵌套

在另一个模块中嵌套模块会影响嵌套模块的名称:

defmodule Foo do defmodule Bar do end end

在上面的例子中,创建了两个模块--Foo和Foo.Bar。 嵌套时,Elixir会自动为内部模块创建一个别名,允许第二个模块Foo.Bar在Bar定义的同一词汇范围(Foo模块)中被访问。

如果Foo.Bar模块移到别的地方,到引用Bar了在Foo模块需要进行更新,以完全限定域名(Foo.Bar)或别名具有对中明确设置Foo的帮助下模块Kernel.SpecialForms.alias/2

defmodule Foo.Bar do # code end defmodule Foo do alias Foo.Bar # code here can refer to "Foo.Bar" as just "Bar" end

模块名称

模块名称可以是任何原子,但Elixir提供了通常用于模块名称的特殊语法。所谓的模块名称是大写ASCII字母,后跟任意数量的小写或大写ASCII字母数字下划线。这个标识符相当于一个前缀为Elixir.。的原子。所以在这个defmodule Foo例子Foo中相当于:"Elixir.Foo"

动态名称

Elixir模块名称可以动态生成。这在使用宏时非常有用。例如,可以写:

defmodule String.to_atom("Foo#{1}") do # contents ... end

只要表达式作为第一个参数传递defmodule/2给一个原子,Elixir将接受任何模块名称。请注意,当使用动态名称时,Elixir不会在当前模块下嵌套名称,也不会自动设置别名。

defoverridable(keywords_or_behaviour)(宏)

使当前模块中的给定函数可覆盖。

一个可重写的函数被懒惰地定义,允许开发人员覆盖它。

defmodule DefaultMod do defmacro __using__(_opts) do quote do def test(x, y) do x + y end defoverridable [test: 2] end end end defmodule InheritMod do use DefaultMod def test(x, y) do x * y + super(x, y) end end

如上例所示,super可用于调用默认实现。

如果@behaviour已经定义,defoverridable也可以用模块作为参数来调用。所有从调用上的行为实现的回调defoverridable将被标记为可覆盖。

defmodule Behaviour do @callback foo :: any end defmodule DefaultMod do defmacro __using__(_opts) do quote do @behaviour Behaviour def foo do "Override me" end defoverridable Behaviour end end end defmodule InheritMod do use DefaultMod def foo do "Overriden" end end

defp(call,expr \ nil)(宏)

用给定的名称和正文定义一个私有函数。

专用功能只能从定义它们的模块中访问。尝试从模块外部访问私有函数会导致UndefinedFunctionError异常。

检查def/2更多信息。

例子

defmodule Foo do def bar do sum(1, 2) end defp sum(a, b), do: a + b end Foo.bar #=> 3 Foo.sum(1, 2) #=> ** (UndefinedFunctionError) undefined function Foo.sum/2

defprotocol(name,do_block)(宏)

定义一个协议。

协议指定了一个应该由其实现定义的API。

例子

在Elixir中,我们有两个用于检查数据结构中有多少项的动词:lengthsizelength意味着必须计算信息。例如,length(list)需要遍历整个列表来计算其长度。在另一方面,tuple_size(tuple)byte_size(binary)作为大小信息的数据结构中预先计算不依赖于元组和二进制文件的大小。

尽管Elixir包含特定的功能tuple_sizebinary_size并且map_size有时我们希望能够检索数据结构的大小,而不管其类型如何。在Elixir中,我们可以使用协议编写多态代码,即可以使用不同形状/类型的代码。大小协议可以实现如下:

defprotocol Size do @doc "Calculates the size (and not the length!) of a data structure" def size(data) end

现在该协议可以针对每个数据结构实施,该协议可能具有符合以下要求的实施:

defimpl Size, for: BitString do def size(binary), do: byte_size(binary) end defimpl Size, for: Map do def size(map), do: map_size(map) end defimpl Size, for: Tuple do def size(tuple), do: tuple_size(tuple) end

注意,我们没有为列表实现它,因为我们没有size列表上的信息,而是它的值需要用来计算length

有可能为所有Elixir类型实现协议:

  • 结构(见下文)

  • Tuple

  • Atom

  • List

  • BitString

  • Integer

  • Float

  • Function

  • PID

  • Map

  • Port

  • Reference

  • Any (如下)

协议和结构

协议的真正好处是与结构混合在一起。 例如,Elixir附带有许多数据类型,如MapSet。 我们也可以为这些类型实现Size协议:

defimpl Size, for: MapSet do def size(map_set), do: MapSet.size(map_set) end

在实现结构的协议时,:for如果defimpl调用位于定义结构的模块内部,则该选项可以省略:

defmodule User do defstruct [:email, :name] defimpl Size do def size(%User{}), do: 2 # two fields end end

如果没有找到给定类型的协议实现,则调用该协议将会引发,除非它被配置为回退到Any。在现有的基础上构建实现的便利也可用,请查看defstruct/1有关派生协议的更多信息。

回退到任何地方

在某些情况下,为所有类型提供默认实现可能会很方便。这可以通过在协议定义中设置@fallback_to_any属性来实现true

defprotocol Size do @fallback_to_any true def size(data) end

Size协议现在可以用于Any

defimpl Size, for: Any do def size(_), do: 0 end

虽然上面的实现可能是不合理的。例如,说一个PID或一个整数的大小为0是没有意义的。这@fallback_to_any就是选择加入行为的原因之一。对于大多数协议,当协议未实现时引发错误是正确的行为。

类型

定义一个协议会自动定义一个名为的类型t,可以按如下方式使用:

@spec print_size(Size.t) :: :ok def print_size(data) do IO.puts(case Size.size(data) do 0 -> "data has no items" 1 -> "data has one item" n -> "data has #{n} items" end) end

@spec上述表示,允许以实现给定协议的所有类型是有效的参数类型为给定的功能。

反射

任何协议模块都包含三个额外功能:

  • __protocol__/1-返回协议名称时:name,给出与所述协议的功能和它们的arities关键字列表时:functions给出,并且当实现的列表:impls给出

  • impl_for/1- 接收结构并返回实现该结构协议的模块,nil否则返回

  • impl_for!/1- 与上面相同,但如果未找到实现会引发错误

  • exit(:normal)

  • exit(:shutdown)

  • exit{:shutdown, term})

出于任何其他原因被认为是不正常的,并被视为崩溃。这意味着默认的主管行为开始了,发布了错误报告等。

这种行为在许多不同的地方依赖。例如,ExUnit使用exit(:shutdown)退出测试过程来表示链接过程,监督树等也要礼貌地关闭。

CLI退出

建立在上述退出信号的基础上,如果由命令行启动的进程因上述三种原因而退出,则其退出被认为是正常的,并且操作系统进程将以状态0退出。

但是,可以通过调用以下操作来定制操作系统出口信号:

exit{:shutdown, integer})

这将导致操作系统进程退出,integer同时通知所有链接的OTP进程有礼貌地关闭。

任何其他退出原因都会导致操作系统进程退出时状态1和链接的OTP进程崩溃。

function_exported?(module, function, arity)

function_exported?(module, atom, arity) :: boolean

如果模块已加载并且包含具有给定元素的公共函数,则返回true,否则返回false。

请注意,如果未加载模块,此功能不会加载模块。检查Code.ensure_loaded/1更多信息。

例子

iex> function_exported?(Enum, :member?, 2) true

get_and_update_in(path, fun) (macro)

获取值并通过给定值更新嵌套的数据结构path

这与get_and_update_in / 3类似,只不过路径是通过宏提取的,而不是传递一个列表。 例如:

get_and_update_in(opts[:foo][:bar], &{&1, &1 + 1})

相当于:

get_and_update_in(opts, [:foo, :bar], &{&1, &1 + 1})

请注意,为了使这个宏能够工作,完整的路径必须总能被这个宏看到。请参阅下面的路径部分。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> get_and_update_in(users["john"].age, &{&1, &1 + 1}) {27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}

路径

路径可以以变量,本地或远程调用开始,并且必须后跟一个或多个:

  • foo[bar]-访问密钥barfoo; 如果foo是零,nil则返回

  • foo.bar - 访问地图/结构字段; 如果该字段不存在,则会引发错误

以下是一些有效的路径:

users["john"][:age] users["john"].age User.all["john"].age all_users()["john"].age

这里有一些无效的:

# Does a remote call after the initial value users["john"].do_something(arg1, arg2) # Does not access any key or field users

get_and_update_in(数据,键,函数)

get_and_update_in(structure :: Access.t, keys, (term -> {get_value, update_value} | :pop)) :: {get_value, structure :: Access.t} when keys: [any, ...], update_value: term, get_value: var

获取一个值并更新嵌套结构。

data是一个嵌套结构(即实现该Access行为的映射,关键字列表或结构)。

fun参数接收key(或nil如果key不存在)的值并且必须返回两元素元组:“获取”值(检索到的值,可以在返回之前对其进行操作)以及要存储的新值key。该fun还可以返回:pop,这意味着当前值应从结构中删除并返回。

它使用Access模块根据给定的结构遍历结构keys,除非key是函数。

如果一个键是一个函数,则会调用该函数传递三个参数,即operation(:get_and_update),要访问的数据以及下一个要调用的函数。

这意味着get_and_update_in/3可以扩展以提供自定义查找。缺点是函数不能作为键存储在被访问的数据结构中。

例子

当需要检索当前值(或根据当前值计算的某个值)并在同一时间更新时,此函数非常有用。例如,它可以用来将用户的年龄增加1,并且一次返回以前的年龄:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> get_and_update_in(users, ["john", :age], &{&1, &1 + 1}) {27, %{"john" => %{age: 28}, "meg" => %{age: 23}}}

当其中一个键是一个函数时,该函数被调用。在下面的例子中,我们使用一个函数来获取和递增列表中的所有年龄:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}] iex> all = fn :get_and_update, data, next -> ...> Enum.map(data, next) |> :lists.unzip ...> end iex> get_and_update_in(users, [all, :age], &{&1, &1 + 1}) {[27, 23], [%{name: "john", age: 28}, %{name: "meg", age: 24}]}

如果在调用函数之前的前一个值是nil,函数nil作为一个值接收,并且必须相应地处理它(通过失败或提供一个理智的默认值)。

Access模块附带许多便利访问器函数,如all上面定义的匿名函数。看Access.all/0Access.key/2和其他作为例子。

get_in(data, keys)

get_in(Access.t, [term, ...]) :: term

从嵌套结构获取值。

除非是函数,否则使用Access模块根据给定的结构遍历结构。keyskey

如果一个键是一个函数,则会调用该函数传递三个参数,即operation(:get),要访问的数据以及下一个要调用的函数。

这意味着get_in/2可以扩展以提供自定义查找。缺点是函数不能作为键存储在被访问的数据结构中。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> get_in(users, ["john", :age]) 27

在任何情况下,在中间的回报条目nilnil将返回为每个接入模块:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> get_in(users, ["unknown", :age]) nil

当其中一个键是一个函数时,该函数被调用。在下面的例子中,我们使用一个函数来获取列表中的所有地图:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}] iex> all = fn :get, data, next -> Enum.map(data, next) end iex> get_in(users, [all, :age]) [27, 23]

如果在调用函数之前的前一个值是nil,该函数nil作为一个值接收,并且必须相应地处理它。

hd(list)

hd(nonempty_maybe_improper_list(elem, any)) :: elem when elem: term

返回列表的头部。ArgumentError如果列表为空,则引发。

它适用于不正确的列表。

允许在警卫测试。由编译器内联。

例子

hd([1, 2, 3, 4]) #=> 1 hd([]) #=> ** (ArgumentError) argument error hd([1 | 2]) #=> 1

if(condition, clauses) (macro)

提供一个if/2宏。

这个宏期望第一个参数是一个条件,第二个参数是一个关键字列表。

一个例子

if(foo, do: bar)

在上面的例子中,如果foo的值为真(即既不是false也不为零),bar会被返回。 否则,将返回零。

else可以给出一个选项来指定相反的:

if(foo, do: bar, else: baz)

块示例

也可以将一个块传递给if/2宏。上面的第一个例子将被翻译为:

if foo do bar end

请注意,do/end成为分隔符。第二个例子将转化为:

if foo do bar else baz end

为了比较两个以上的子句,cond/1必须使用该宏。

left in right (macro)

检查左侧的元素是否是右侧集合的成员。

例子

iex> x = 1 iex> x in [1, 2, 3] true

这个运算符(这是一个宏)简单地转换为一个呼叫Enum.member?/2。上面的例子将转化为:

Enum.member?([1, 2, 3], x)

Elixir也支持left not in right,其评估not(left in right)如下:

iex> x = 1 iex> x not in [1, 2, 3] false

Guards

只要右侧是范围或列表,in/2操作员(以及not in)可用于警戒条款。在这种情况下,Elixir会将运营商扩展到有效的警戒表达。例如:

when x in [1, 2, 3]

转化为:

when x === 1 or x === 2 or x === 3

使用范围时:

when x in 1..3

转化为:

when is_integer(x) and x >= 1 and x <= 3

请注意,只有整数可以被考虑在范围in内。

AST 考虑

left not in right 被编译器解析为AST:

{:not, _, [{:in, _, [left, right]}]}

这与AST相同not(left in right)

另外,Macro.to_string/2将把这个AST的所有事件翻译成left not in right

inspect(term, opts \ [])

inspect(Inspect.t, keyword) :: String.t

根据Inspect协议检查给定的参数。第二个参数是一个关键字列表,其中包含控制检查的选项。

选项

inspect/2接受内部翻译为Inspect.Opts结构的选项列表。查看文档Inspect.Opts以查看支持的选项。

例子

iex> inspect(:foo) ":foo" iex> inspect [1, 2, 3, 4, 5], limit: 3 "[1, 2, 3, ...]" iex> inspect [1, 2, 3], pretty: true, width: 0 "[1,\n 2,\n 3]" iex> inspect("olá" <> <<0>>) "<<111, 108, 195, 161, 0>>" iex> inspect("olá" <> <<0>>, binaries: :as_strings) "\"olá\\0\"" iex> inspect("olá", binaries: :as_binaries) "<<111, 108, 195, 161>>" iex> inspect('bar') "'bar'" iex> inspect([0 | 'bar']) "[0, 98, 97, 114]" iex> inspect(100, base: :octal) "0o144" iex> inspect(100, base: :hex) "0x64"

请注意,该Inspect协议不一定会返回Elixir术语的有效表示。在这种情况下,检查结果必须以#。例如,检查一个函数将返回:

inspect fn a, b -> a + b end #=> #Function<...>

is_atom(term)

is_atom(term) :: boolean

如果term是原子则返回true; 否则返回false

允许在警卫测试。由编译器内联。

is_binary(term)

is_binary(term) :: boolean

如果term是二进制则返回true; 否则返回false

二进制文件总是包含完整的字节数。

允许在警卫测试。由编译器内联。

例子

iex> is_binary "foo" true iex> is_binary <<1::3>> false

is_bitstring(项)

is_bitstring(term) :: boolean

如果term是位串(包括二进制),则返回true; 否则返回false

允许在警卫测试。由编译器内联。

例子

iex> is_bitstring "foo" true iex> is_bitstring <<1::3>> true

is_boolean(项)

is_boolean(term) :: boolean

如果term是原子true或原子false,则返回true(即,布尔值); 否则返回false。

允许在警卫测试。由编译器内联。

is_float(项)

is_float(term)::布尔值

如果term是一个浮点数,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_function(项)

is_function(term) :: boolean

如果term是一个函数,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_function(term,arity)

is_function(term,non_neg_integer)::布尔值

如果term是一个可以用参数数量来应用的函数,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

例子

iex> is_function(fn(x) -> x * 2 end, 1) true iex> is_function(fn(x) -> x * 2 end, 2) false

is_integer(项)

is_integer(term) :: boolean

如果term是一个整数,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_list(项)

is_list(term) :: boolean

如果term是包含零个或多个元素的列表,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_map(项)

is_map(term):: boolean

如果term是地图,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_nil(term) (macro)

如果term是零,则返回true,否则返回false。

允许在守卫条款。

例子

iex> is_nil(1) false iex> is_nil(nil) true

is_number(term)

is_number(term) :: boolean

如果term是整数或浮点数,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_pid(项)

is_pid(term) :: boolean

如果term是一个PID(进程标识符),则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_port(项)

is_port(term) :: boolean

如果term是一个端口标识符,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_reference(项)

is_reference(term) :: boolean

如果term是引用,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

is_tuple(term)

is_tuple(term):: boolean

如果term是一个元组,则返回true; 否则返回false。

允许在警卫测试。由编译器内联。

length(list)

length(list) :: non_neg_integer

返回list的长度。

允许在警卫测试。由编译器内联。

例子

iex> length([1, 2, 3, 4, 5, 6, 7, 8, 9]) 9

macro_exported?(module, macro, arity)

macro_exported?(module, atom, arity) :: boolean

如果模块已加载并且包含具有给定元素的公共宏,则返回true,否则返回false。

请注意,如果未加载模块,此功能不会加载模块。检查Code.ensure_loaded/1更多信息。

如果module是Erlang模块(而不是Elixir模块),则此函数始终返回false

例子

iex> macro_exported?(Kernel, :use, 2) true iex> macro_exported?(:erlang, :abs, 1) false

make_ref()

make_ref() :: reference

返回几乎唯一的参考。

大约2 ^ 82次通话后,返回的参考将重新发生; 因此它在实践中足够独特。

由编译器内联。

例子

make_ref() #=> #Reference<0.0.0.135>

map_size(map)

map_size(map) :: non_neg_integer

返回地图的大小。

地图的大小是地图包含的键值对的数量。

此操作在不断的时间内发生。

允许在警卫测试。由编译器内联。

例子

iex> map_size(%{a: "foo", b: "bar"}) 2

match?(pattern, expr) (macro)

一个方便的宏,用于检查右侧(表达式)是否匹配左侧(一个模式)。

例子

iex> match?(1, 1) true iex> match?(1, 2) false iex> match?{1, _}, {1, 2}) true iex> map = %{a: 1, b: 2} iex> match?(%{a: _}, map) true iex> a = 1 iex> match?(^a, 1) true

match?/2 过滤在枚举中查找值时非常有用:

iex> list = [a: 1, b: 2, a: 3] iex> Enum.filter(list, &match?{:a, _}, &1)) [a: 1, a: 3]

警卫条款也可以用于比赛:

iex> list = [a: 1, b: 2, a: 3] iex> Enum.filter(list, &match?{:a, x} when x < 2, &1)) [a: 1]

但是,在匹配中分配的变量在函数调用之外将不可用(与=运算符匹配的常规模式不同):

iex> match?(_x, 1) true iex> binding() []

max(first, second)

max(first, second) :: first | second when first: term, second: term

根据Erlang的术语顺序,返回两个给定项中最大的一个。

如果术语比较相等,则返回第一个。

由编译器内联。

例子

iex> max(1, 2) 2 iex> max(:a, :b) :b

min(first, second)

min(first, second) :: first | second when first: term, second: term

根据Erlang的术语顺序,返回两个给定项中最小的一个。

如果术语比较相等,则返回第一个。

由编译器内联。

例子

iex> min(1, 2) 1 iex> min("foo", "bar") "bar"

节点()

node() :: node

返回表示本地节点名称的原子。如果节点不活动,则返回:nonode@nohost

允许在警卫测试。由编译器内联。

节点(ARG)

node(pid | reference | port) :: node

返回给定参数所在的节点。参数可以是PID,参考或端口。如果本地节点不活动,则返回:nonode@nohost

允许在警卫测试。由编译器内联。

没有值

not false :: true

not true :: false

非布尔值。

arg必须是一个布尔值; 如果不是,则会引发异常ArgumentError

允许在警卫测试。由编译器内联。

例子

iex> not false true

left or right (macro)

布尔或。

如果第一个参数是truetrue则被返回; 否则,返回第二个参数。

由于短路,只需要第一个参数为布尔值。如果第一个参数不是布尔值,ArgumentError则会引发异常。

允许在警卫测试。

例子

iex> true or false true iex> false or 42 42

pop_in(路径)(宏)

通过给定的嵌套结构弹出一个键path

这与之类似pop_in/2,除了通过宏提取路径而不是传递列表。例如:

pop_in(opts[:foo][:bar])

相当于:

pop_in(opts, [:foo, :bar])

请注意,为了使这个宏能够工作,完整的路径必须总能被这个宏看到。有关支持的路径表达式的更多信息,请查看get_and_update_in/2文档。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> pop_in(users["john"][:age]) {27, %{"john" => %{}, "meg" => %{age: 23}}} iex> users = %{john: %{age: 27}, meg: %{age: 23}} iex> pop_in(users.john[:age]) {27, %{john: %{}, meg: %{age: 23}}}

在任何条目返回的情况下nil,其密钥将被删除,删除将被视为成功。

pop_in(数据,键)

pop_in(data, [Access.get_and_update_fun(term, data) | term, ...]) :: {term, data} when data: Access.container

从给定的嵌套结构中弹出一个键。

使用Access协议根据给定的键遍历结构,除非键是函数。 如果该键是一个函数,它将按照get_and_update_in / 3中的指定进行调用。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> pop_in(users, ["john", :age]) {27, %{"john" => %{}, "meg" => %{age: 23}}}

在任何条目返回的情况下nil,其密钥将被删除,删除将被视为成功。

put_elem(元组,索引,值)

put_elem(tuple, non_neg_integer, term) :: tuple

插入value从零开始在给定indextuple

由编译器内联。

例子

iex> tuple = {:foo, :bar, 3} iex> put_elem(tuple, 0, :baz) {:baz, :bar, 3}

put_in(路径,值)(宏)

通过给定的值在嵌套结构中放置一个值path

这与put_in/3类似,除了通过宏提取路径而不是传递列表。例如:

put_in(opts[:foo][:bar], :baz)

相当于:

put_in(opts, [:foo, :bar], :baz)

请注意,为了使这个宏能够工作,完整的路径必须总能被这个宏看到。有关支持的路径表达式的更多信息,请查看get_and_update_in/2文档。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> put_in(users["john"][:age], 28) %{"john" => %{age: 28}, "meg" => %{age: 23}} iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> put_in(users["john"].age, 28) %{"john" => %{age: 28}, "meg" => %{age: 23}}

put_in(数据,键,值)

put_in(Access.t, [term, ...], term) :: Access.t

在嵌套结构中放置一个值。

使用Access模块根据给定的键遍历结构,除非键是函数。 如果该键是一个函数,它将按照get_and_update_in / 3中的指定进行调用。

例子

iex> users =%{“john”=>%{age:27},“meg”=>%{age:23}} iex> put_in(users,[“john”,:age],28) %{“john”=>%{age:28},“meg”=>%{age:23}}

如果中间的任何条目返回nil,则下一次尝试访问时会出现错误。

raise(message) (macro)

引发一个例外。

如果参数msg是二进制文件,则会RuntimeError使用给定参数作为消息引发异常。

如果msg是一个原子,它只需要以atom作为第一个参数并将[]作为第二个参数来调用raise / 2。

如果msg是一个异常结构,它会按原样产生。

如果msg还有其他事情,raise将会失败,并发生ArgumentError异常。

例子

iex> raise "oops" ** (RuntimeError) oops try do 1 + :foo rescue x in [ArithmeticError] -> IO.puts "that was expected" raise x end

raise(exception, attributes) (macro)

引发一个例外。

在给定参数(必须是模块名称,如ArgumentError或RuntimeError)上传递attrs作为属性以检索异常结构时调用异常/ 1函数。

任何包含对defexception/1宏的调用的模块都会自动实现Exception.exception/1预期的回调raise/2。有关更多信息,请参阅defexception/1

例子

iex> raise(ArgumentError, message: "Sample") ** (ArgumentError) Sample

rem(dividend, divisor)

rem(integer, neg_integer | pos_integer) :: integer

计算整数除法的其余部分。

rem/2使用截断除法,这意味着结果将始终具有符号dividend

如果其中一个参数不是整数,或者除数为0,则引发ArithmeticError异常。

允许在警卫测试。由编译器内联。

例子

iex> rem(5, 2) 1 iex> rem(6, -4) 2

reraise(message, stacktrace) (macro)

引发一个保存前一个堆栈跟踪的异常。

适用raise/1但不会生成新的堆栈跟踪。

注意System.stacktrace/0返回最后一个异常的栈跟踪。也就是说,将stacktrace分配为rescue子句中的第一个表达式是常见的,因为rescue子句和raise调用之间可能引发(并拯救)的任何其他异常可能会更改该System.stacktrace/0值。

例子

try do raise "oops" rescue exception -> stacktrace = System.stacktrace if Exception.message(exception) == "oops" do reraise exception, stacktrace end end

reraise(exception, attributes, stacktrace) (macro)

引发一个保存前一个堆栈跟踪的异常。

reraise / 3像reraise / 2一样工作,除了它将参数传递给异常/ 1函数(如raise / 2中所述)。

例子

try do raise "oops" rescue exception -> stacktrace = System.stacktrace reraise WrapperError, [exception: exception], stacktrace end

round(number)

round(value) :: value when value: integer

round(float) :: integer

将数字四舍五入为最接近的整数。

允许在警卫测试。由编译器内联。

例子

iex> round(5.6) 6 iex> round(5.2) 5 iex> round(-9.9) -10 iex> round(-9) -9

self()

self() :: pid

返回调用进程的PID(进程标识符)。

允许在守卫条款。由编译器内联。

send(dest, message)

send(dest :: pid | port | atom | {atom, node}, message) :: message when message: any

将消息发送给给定的dest并返回消息。

dest可以是远程或本地PID,(本地)端口,本地注册的名称或{registered_name, node}用于另一个节点处的注册名称的元组。

由编译器内联。

例子

iex> send self(), :hello :hello

sigil_C(term, modifiers) (macro)

处理印记~C

它只是返回一个charlist而不会转义字符和插值。

例子

iex> ~C(foo) 'foo' iex> ~C(f#{o}o) 'f\#{o}o'

sigil_D(date, modifiers) (macro)

处理~D日期的印记。

小写~d变体不存在,因为插值和转义字符对日期标记没有用处。

例子

n阶>〜d [2015年1月13日] 〜d [2015年1月13日]

sigil_N(日期,修饰符)(宏)

处理~N单纯时间的印记。

小写~n变体不存在,因为插值和转义字符对日期时间标记没有用处。

例子

iex> ~N[2015-01-13 13:00:07] ~N[2015-01-13 13:00:07] iex> ~N[2015-01-13T13:00:07.001] ~N[2015-01-13 13:00:07.001]

sigil_R(术语,修饰符)(宏)

处理印记~R

它返回一个正则表达式模式而不会转义或解释插值。

有关正则表达式的更多信息可以在Regex模块中找到。

例子

iex> Regex.match?(~R(f#{1,3}o), "f#o") true

sigil_S(term, modifiers) (macro)

处理印记~S

它只是返回一个字符串而不会转义字符,也不会插入。

例子

iex> ~S(foo) "foo" iex> ~S(f#{o}o) "f\#{o}o"

sigil_T(date, modifiers) (macro)

处理~T时间印记。

小写~t变体不存在,因为插值和转义字符对时间标记没有用处。

例子

iex> ~T[13:00:07] ~T[13:00:07] iex> ~T[13:00:07.001] ~T[13:00:07.001]

sigil_W(term, modifiers) (macro)

处理印记~W

它返回一个由空格分隔的“单词”列表,不会转义或解释插值。

修饰符

  • s:列表中的单词是字符串(默认)

  • a:列表中的单词是原子

  • c:列表中的单词是charlists

例子

iex> ~W(foo #{bar} baz) ["foo", "\#{bar}", "baz"]

sigil_c(term, modifiers) (macro)

处理印记~c

它返回一个charlist,就好像它是一个单引号字符串,不需要转义字符并替换插值。

例子

iex> ~c(foo) 'foo' iex> ~c(f#{:o}o) 'foo' iex> ~c(f\#{:o}o) 'f\#{:o}o'

sigil_r(term, modifiers) (macro)

处理印记~r

它返回正则表达式模式,消除字符并替换插值。

有关正则表达式的更多信息可以在Regex模块中找到。

例子

iex> Regex.match?(~r(foo), "foo") true iex> Regex.match?(~r/abc/, "abc") true

sigil_s(term, modifiers) (macro)

处理印记~s

它返回一个字符串,就好像它是一个双引号字符串,避免了字符和替换插值。

例子

iex> ~s(foo) "foo" iex> ~s(f#{:o}o) "foo" iex> ~s(f\#{:o}o) "f\#{:o}o"

sigil_w(term, modifiers) (macro)

处理印记~w

它返回一个由空格分隔的“单词”列表。对每个单词都进行字符消隐和内插。

修饰符

  • s:列表中的单词是字符串(默认)

  • a:列表中的单词是原子

  • c:列表中的单词是charlists

例子

iex> ~w(foo #{:bar} baz) ["foo", "bar", "baz"] iex> ~w(foo #{" bar baz "}) ["foo", "bar", "baz"] iex> ~w(--source test/enum_test.exs) ["--source", "test/enum_test.exs"] iex> ~w(foo bar baz)a [:foo, :bar, :baz]

spawn(fun)

spawn((() -> any)) :: pid

产生给定的函数并返回它的PID。

通常,开发人员不使用spawn函数,而是使用构建在spawn之上的抽象函数(如Task,GenServer和Agent),这些抽象函数在内省和调试方面产生更多便利。

检查Process模块以获取更多与过程相关的功能。

匿名函数接收0个参数,并且可以返回任何值。

由编译器内联。

例子

current = self() child = spawn(fn -> send current, {self(), 1 + 2} end) receive do {^child, 3} -> IO.puts "Received 3 back" end

spawn(module, fun, args)

spawn(module, atom, list) :: pid

产卵给定函数fun从给定的module传递给定的args,并返回其PID。

通常,开发商不使用spawn的功能,而不是他们使用的抽象,例如TaskGenServerAgent,建在上面spawn,会派生更多的便利流程内省和调试方面。

检查Process模块以获取更多与过程相关的功能。

由编译器内联。

例子

spawn(SomeModule, :function, [1, 2, 3])

spawn_link(fun)

spawn_link((() -> any)) :: pid

生成给定的函数,将其链接到当前进程,并返回其PID。

通常,开发人员不使用spawn函数,而是使用构建在spawn之上的抽象函数(如Task,GenServer和Agent),这些抽象函数在内省和调试方面产生更多便利。

检查Process模块以获取更多与过程相关的功能。有关链接的更多信息,请检查Process.link/1

匿名函数接收0个参数,并且可以返回任何值。

由编译器内联。

例子

current = self() child = spawn_link(fn -> send(current, {self(), 1 + 2}) end) receive do {^child, 3} -> IO.puts "Received 3 back" end

spawn_link(module, fun, args)

spawn_link(module, atom, list) :: pid

根据给定的给定函数传递给定函数funmodule将其args链接到当前进程并返回其PID。

通常,开发人员不使用spawn函数,而是使用构建在spawn之上的抽象函数(如Task,GenServer和Agent),这些抽象函数在内省和调试方面产生更多便利。

检查Process模块以获取更多与过程相关的功能。有关链接的更多信息,请检查Process.link/1

由编译器内联。

例子

spawn_link(SomeModule, :function, [1, 2, 3])

spawn_monitor(fun)

spawn_monitor((() -> any)) :: {pid, reference}

生成给定的函数,监视它并返回其PID和监视参考。

通常,开发人员不使用spawn函数,而是使用构建在spawn之上的抽象函数(如Task,GenServer和Agent),这些抽象函数在内省和调试方面产生更多便利。

检查Process模块以获取更多与过程相关的功能。

匿名函数接收0个参数,并且可以返回任何值。

由编译器内联。

例子

current = self() spawn_monitor(fn -> send current, {self(), 1 + 2} end)

spawn_monitor(module, fun, args)

spawn_monitor(module, atom, list) :: {pid, reference}

产生给定的模块和函数传递给定的参数,监视它并返回其PID和监视参考。

通常,开发商不使用spawn的功能,而不是他们使用的抽象,例如TaskGenServerAgent,建在上面spawn,会派生更多的便利流程内省和调试方面。

检查Process模块以获取更多与过程相关的功能。

由编译器内联。

例子

spawn_monitor(SomeModule, :function, [1, 2, 3])

struct(struct, fields \ [])

struct(module | struct, Enum.t) :: struct

创建并更新结构。

所述struct参数可以是一个原子(其定义defstruct)或struct本身。第二个参数是任何Enumerable在枚举过程中发出两元元组(键 - 值对)的元素。

Enumerable中不存在于结构中的键将被自动丢弃。 请注意,键必须是原子,因为定义结构时只允许使用原子。

此功能对于动态创建和更新结构以及将地图转换为结构非常有用; 在后一种情况下,只需:__struct__在地图中插入适当的字段可能不够,struct/2应该使用它。

例子

defmodule User do defstruct name: "john" end struct(User) #=> %User{name: "john"} opts = [name: "meg"] user = struct(User, opts) #=> %User{name: "meg"} struct(user, unknown: "value") #=> %User{name: "meg"} struct(User, %{name: "meg"}) #=> %User{name: "meg"} # String keys are ignored struct(User, %{"name" => "meg"}) #=> %User{name: "john"}

struct!(struct, fields \ [])

struct!(module | struct, Enum.t) :: struct | no_return

类似于struct/2但检查关键有效性。

该函数struct!/2模拟结构体的编译时行为。这意味着:

  • 当构建一个结构体struct!(SomeStruct, key: :value)时它就等价于%SomeStruct{key: :value},因此这个函数将检查每个给定的键值是否属于该结构体。如果结构正在执行任何密钥通过@enforce_keys,那么这些也将被强制执行;

  • 当更新一个结构体时,struct!(%SomeStruct{}, key: :value)就等同于%SomeStruct{struct | key: :value},因此这个函数将检查每个给定的键值是否属于该结构体。但是,更新结构不强制执行密钥,因为密钥仅在构建时才执行;

throw(term)

throw(term) :: no_return

来自函数的非本地返回。

检查Kernel.SpecialForms.try/1更多信息。

由编译器内联。

tl(list)

tl(nonempty_maybe_improper_list(elem, tail)) :: maybe_improper_list(elem, tail) | tail when elem: term, tail: term

返回列表的尾部。如果列表为空,则引发ArgumentError

它适用于不正确的列表。

允许在警卫测试。由编译器内联。

例子

tl([1, 2, 3, :go]) #=> [2, 3, :go] tl([]) #=> ** (ArgumentError) argument error tl([:one]) #=> [] tl([:a, :b | :c]) #=> [:b | :c] tl([:a | %{b: 1}]) #=> %{b: 1}

to_charlist(term) (macro)

根据List.Chars协议将给定的术语转换为charlist 。

例子

iex> to_charlist(:foo) 'foo'

to_string(term) (macro)

根据String.Chars协议将参数转换为字符串。

这是在有字符串插值时调用的函数。

例子

iex> to_string(:foo) "foo"

trunc(number)

trunc(float) :: integer

trunc(value) :: value when value: integer

返回整数部分number

允许在警卫测试。由编译器内联。

例子

iex> trunc(5.4) 5 iex> trunc(-5.99) -5 iex> trunc(-5) -5

tuple_size(tuple)

tuple_size(tuple) :: non_neg_integer

返回元组的大小。

此操作在不断的时间内发生。

允许在警卫测试。由编译器内联。

例子

iex> tuple_size {:a, :b, :c} 3

unless(condition, clauses) (macro)

提供一个unless宏。

此宏评估并返回do作为第二个参数传入的块,除非clause求值为true。否则,它返回else块的值(如果存在的话)或者否则返回nil

另见if/2

例子

iex> unless(Enum.empty?([]), do: "Hello") nil iex> unless(Enum.empty?([1, 2, 3]), do: "Hello") "Hello" iex> unless Enum.sum([2, 2]) == 5 do ...> "Math still works" ...> else ...> "Math is broken" ...> end "Math still works"

update_in(path, fun) (macro)

通过给定的更新嵌套结构path

这与update_in/3类似,除了通过宏提取路径而不是传递列表。例如:

update_in(opts[:foo][:bar], &(&1 + 1))

相当于:

update_in(opts, [:foo, :bar], &(&1 + 1))

请注意,为了使这个宏能够工作,完整的路径必须总能被这个宏看到。有关支持的路径表达式的更多信息,请查看get_and_update_in/2文档。

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> update_in(users["john"][:age], &(&1 + 1)) %{"john" => %{age: 28}, "meg" => %{age: 23}} iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> update_in(users["john"].age, &(&1 + 1)) %{"john" => %{age: 28}, "meg" => %{age: 23}}

update_in(data, keys, fun)

update_in(Access.t, [term, ...], (term -> term)) :: Access.t

更新嵌套结构中的密钥。

除非是函数,否则使用Access模块根据给定的结构遍历结构。如果该键是一个函数,它将按照中指定的方式被调用。keyskeyget_and_update_in/3

例子

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}} iex> update_in(users, ["john", :age], &(&1 + 1)) %{"john" => %{age: 28}, "meg" => %{age: 23}}

如果中间的任何条目返回nil,则下一次尝试访问时会出现错误。

use(module, opts \ []) (macro)

在当前上下文中使用给定的模块。

调用时:

use MyModule, some: :options

调用MyModule模块中的__using __ / 1宏,并传递第二个参数作为参数。 由于__using __ / 1是一个宏,所有常用的宏规则都适用,并且它的返回值应该是带引号的代码,然后插入调用use / 2的地方。

例子

例如,为了使用ExUnitElixir提供的框架编写测试用例,开发人员应该使用use以下ExUnit.Case模块:

defmodule AssertionTest do use ExUnit.Case, async: true test "always pass" do assert true end end

在这个例子中,ExUnit.Case.__using__/1以关键字列表[async: true]作为参数被调用; use/2转化为:

defmodule AssertionTest do require ExUnit.Case ExUnit.Case.__using__([async: true]) test "always pass" do assert true end end

ExUnit.Case然后将定义__using__/1宏:

defmodule ExUnit.Case do defmacro __using__(opts) do # do something with opts quote do # return some code to inject in the caller end end end

最佳实践

__using__/1通常在需要将某些状态(通过模块属性)或回调(例如@before_compile,请参阅文档以Module获取更多信息)设置给调用者时使用。

__using__/1 也可以用于别名,要求或从不同模块导入功能:

defmodule MyModule do defmacro __using__(_opts) do quote do import MyModule.Foo import MyModule.Bar import MyModule.Baz alias MyModule.Repo end end end

但是,如果它只是导入,别名或需要模块本身,请不要提供__using __ / 1。 例如,避免这种情况:

defmodule MyModule do defmacro __using__(_opts) do quote do import MyModule end end end

在这种情况下,开发人员应该直接导入或别名模块,以便他们可以按自己的意愿自定义这些模块,而不需要间接寻址use/2

最后,开发人员还应该避免在__using__/1回调中定义函数,除非这些函数是以前定义的默认实现@callback或者是被覆盖的函数(请参阅参考资料defoverridable/1)。即使在这些情况下,定义函数也应该被视为“最后的手段”。

如果您想为用户模块提供一些现有功能,请将其定义在将相应导入的模块中; 例如,ExUnit.Case没有定义test/3调用的模块中的宏use ExUnit.Case,但是它定义ExUnit.Case.test/3并在使用时将其导入到调用者中。

var!(var, context \ nil) (macro)

在引用中使用时,标记给定的变量不应卫生。

参数可以是一个未加引号的变量,也可以是标准元组形式{name, meta, context}

检查Kernel.SpecialForms.quote/2更多信息。

left |> right (macro)

管道运营商。

该运算符在左侧引入表达式作为右侧函数调用的第一个参数。

例子

iex> [1, [2], 3] |> List.flatten() [1, 2, 3]

上面的例子与调用List.flatten([1, [2], 3])相同

|>当需要执行一系列类似于流水线的操作时,操作员非常有用:

iex> [1, [2], 3] |> List.flatten |> Enum.map(fn x -> x * 2 end) [2, 4, 6]

在上面的例子中,列表[1, [2], 3]作为List.flatten/1函数的第一个参数传递,然后扁平化列表作为Enum.map/2函数的第一个参数传递给函数,该函数将列表中的每个元素加倍。

换句话说,上述表达式简单地转换为:

Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)

陷阱

使用管道操作员时有两个常见的缺陷。

第一个与运营商优先权有关。例如,下面的表达式:

String.graphemes "Hello" |> Enum.reverse

转换为:

String.graphemes("Hello" |> Enum.reverse)

这会导致错误,因为该Enumerable协议未针对二进制文件定义。添加明确的括号可以消除模糊性:

String.graphemes("Hello") |> Enum.reverse

或者,甚至更好:

"Hello" |> String.graphemes |> Enum.reverse

第二个缺陷是|>运营商致力于通话。例如,当你写:

"Hello" |> some_function()

Elixir看到右侧是一个函数调用并将其传递给它。这意味着,如果你想管道到一个匿名或捕获的函数,它也必须显式调用。

鉴于匿名功能:

fun = fn x -> IO.puts(x) end fun.("Hello")

这不会起作用,因为它会尝试调用本地函数fun

"Hello" |> fun()

这工作:

"Hello" |> fun.()

正如你所看到的,|>操作符保留了与不使用管道时相同的语义,因为两者都需要fun.(...)符号。

left || right (macro)

提供一个短路运算符,仅当第一个表达式不计算为true(即,它是nilfalse)时才评估并返回第二个表达式。否则返回第一个表达式。

警卫条款不允许。

例子

iex> Enum.empty?([1]) || Enum.empty?([1]) false iex> List.first([]) || true true iex> Enum.empty?([1]) || 1 1 iex> Enum.empty?([]) || throw(:bad) true

请注意,与or/2此不同,此运算符接受任何表达式作为第一个参数,而不仅仅是布尔值。