Elixir 带有保护子句的内省函数

Elixir 带有保护子句的内省函数,elixir,introspection,guard-clause,Elixir,Introspection,Guard Clause,给定一个模块有两个具有相同算术性但不同保护子句的函数,我(理想情况下)如何看到这些子句是什么,或者至少有两个函数 defmodule Test do def greet(name) when name == "foo" do IO.puts("Hello, bar") end def greet(name), do: IO.puts("Hello, #{name}") end Test.\uuu info(:functions)不起作用,因为它只返回[greet:1]您可

给定一个模块有两个具有相同算术性但不同保护子句的函数,我(理想情况下)如何看到这些子句是什么,或者至少有两个函数

defmodule Test do
  def greet(name) when name == "foo" do
    IO.puts("Hello, bar")
  end

  def greet(name), do: IO.puts("Hello, #{name}")
end

Test.\uuu info(:functions)
不起作用,因为它只返回
[greet:1]

您可以将模块的代码反编译为“抽象代码”,并深入挖掘以获取此信息。下面是如何获取模块中每个函数的子句:

module = Test

{:ok, {^module, [abstract_code: {:raw_abstract_v1, abstract_code}]}} = :beam_lib.chunks(module, [:abstract_code])

for {:function, _, name, arity, clauses} <- abstract_code do
  # Uncomment the next line to print the AST of the clauses.
  # IO.inspect(clauses)
  IO.inspect {name, arity, length(clauses)}
end

注意:这可能是私有API,在Erlang/OTP的未来版本中可能会更改。上述输出在Erlang/OTP 20上。

如果模块是第三方和/或已经编译,请参考@Dogbert提供的答案

如果模块是自有的,则可以在编译阶段使用钩子收集请求的信息:

defmodule TestInfo do
定义上的定义(_环境、种类、名称、参数、防护装置、主体)是否
使用{:ok,table}[]
[] -> []
列表何时为列表(列表)->列表[名称]
结束
:dets.insert(表,{name,[{kind,args,guards}|子句]})
:dets.close(表)
结束
结束
结束
defmoduletestdo
@关于定义{TestInfo,:关于定义}⇐ 这
当name==“foo”do时,def问候(name)
IO.puts(“你好,酒吧”)
结束
def greet(name),do:IO.puts(“Hello,#{name}”)
结束
现在,所有定义都存储在DETS中:

{:ok,table}=:dets.open_文件(:test_info,type::set)
:dets.lookup(表,:greet)
#⇒ [
#问候:[
#{:def,[{:name,[line:10],nil}],[]},
#{:def,[{:name,[line:6],nil}],
#[{:==,[line:6],{:name,[line:6],nil},“foo”]}]
#  ]
:dets.close(表)
我使用DETS来存储信息,因为它存储在编译阶段,典型的用法是在运行时

{:__info__, 1, 7}
{:greet, 1, 2}