鉴于此代码:
defmodule MyModule do
def my_func(<< part::binary-size(size), rest::binary >>, size) do
IO.puts(part)
end
def my_func_2(size, << part::binary-size(size), rest::binary >>) do
IO.puts(part)
end
def my_func_3(size, << part::binary-size(size-1), rest::binary >>) do
IO.puts(part)
end
end
该模块不会编译。如果我注释掉除了一个以外的所有函数,我会得到不同的错误:
使用my_func/1
进行编译时出现此错误:
warning: variable "size" does not exist and is being expanded to "size()", please use parentheses to remove the ambiguity or change the variable name
my_script.exs:2
** (CompileError) my_script.exs:2: size in bitstring expects an integer or a variable as argument, got: size()
(elixir) src/elixir_bitstring.erl:52: :elixir_bitstring.expand_bit_info/5
(elixir) src/elixir_bitstring.erl:29: :elixir_bitstring.expand_bitstr/4
(elixir) src/elixir_bitstring.erl:10: :elixir_bitstring.expand/3
(stdlib) lists.erl:1354: :lists.mapfoldl/3
使用my_func_2/1
进行编译会给我带来另一个错误:
** (CompileError) my_script.exs:6: variable size@1 is unbound
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
使用my_func_3/1
进行编译会给我一个不同的错误:
** (CompileError) my_script.exs:10: size in bitstring expects an integer or a variable as argument, got: :erlang.-(size, 1)
(elixir) src/elixir_bitstring.erl:52: :elixir_bitstring.expand_bit_info/5
(elixir) src/elixir_bitstring.erl:29: :elixir_bitstring.expand_bitstr/4
(elixir) src/elixir_bitstring.erl:10: :elixir_bitstring.expand/3
(stdlib) lists.erl:1354: :lists.mapfoldl/3
(stdlib) lists.erl:1355: :lists.mapfoldl/3
有人可以向我解释所有错误吗?在erlang编译器级别发生了什么以及为什么?
答案 0 :(得分:2)
Erlang和Elixir欺骗我们相信我们可以在每个数据结构上进行嵌套模式匹配,但二进制文件是一个例外。 Here你可以阅读
二进制模式不能嵌套(...)段具有以下一般语法:
Value:Size/TypeSpecifierList
匹配
Value
时,value必须是变量或整数,或浮点文字。表达是不允许的。大小必须是整数文字或先前绑定的变量。以下是不允许的:
foo(N, <<X:N,T/binary>>) -> {X,T}.
两次出现的N无关。编译器会抱怨size字段中的N是未绑定的。
编写此示例的正确方法如下:
foo(N, Bin) -> <<X:N,T/binary>> = Bin, {X,T}.
Elixir也是如此。
所以在my_func
编译时,不会尝试在第一个参数之后查看函数头,并且说没有名为size
的变量。它认为它可能是一个函数,然后编译器出现错误,说size in bitstring expects an integer or a variable as argument
。
在my_func_2
中,事情变得棘手,因为变量存在于第一个参数中,但它尚未绑定。这正是上面Erlang文档的情况。您无法在尺寸上进行模式匹配。它必须是先前绑定的变量。名称size@1
暗示您编译器不会将这两个视为同一个变量。它们内部有不同的名称。
在my_func_3
编译器中看到有一个减法因此它不会检查变量,并立即报告你不能在二进制模式匹配中使用表达式。
解决此限制的正确方法也在引用部分中。