这是Elixir 1.3中最小的破坏示例:
defmodule Foo do @type t :: %__MODULE__{x: non_neg_integer} defstruct x: 0 @spec test(t) :: t def test(%__MODULE__{} = foo), do: test2(foo) @spec test2(t) :: t defp test2(%__MODULE__{} = foo), do: %__MODULE__{foo | x: 5} end
这无法使用以下方式键入check : foo.ex:9: The variable _@1 can never match since previous clauses completely covered the type #{'__struct__':='Elixir.Foo', _=>_}
.
我搜索和搜索过,不能为我的生活找到解释这意味着什么,或如何解决它.
如果您将代码简化为:
defmodule Foo do @type t :: %__MODULE__{x: non_neg_integer} defstruct x: 0 @spec set_x_to_5(t) :: t def set_x_to_5(%__MODULE__{} = foo), do: %__MODULE__{foo | x: 5} end
然后反编译生成的.beam文件,得到:
set_x_to_5(#{'__struct__' := 'Elixir.Foo'} = foo@1) -> case foo@1 of _@1 = #{'__struct__' := 'Elixir.Foo'} -> _@1#{x := 5}; _@1 -> erlang:error({badstruct, 'Elixir.Foo', _@1}) end.
如果您仔细查看case
Elixir生成的语句%__MODULE__{foo | x: 5}
,您将看到它包含一个永远不能匹配的分支,因为__struct__
它保证Foo
在该函数内部.这是由Elixir生成的,因为如果您使用具有不同结构的%Struct{map | ...}
语法,Elixir会抛出错误map
:
iex(1)> defmodule Foo, do: defstruct [:x] iex(2)> defmodule Bar, do: defstruct [:x] iex(3)> %Foo{%Bar{x: 1} | x: 2} ** (BadStructError) expected a struct named Foo, got: %Bar{x: 1}
要解决此问题,您可以删除该__MODULE__
部件,然后执行以下操作:
%{foo | x: 5}
结果将是相同的,你将得到没有警告.