Debugging 为什么elixir调试器在调用内置函数而不是我的函数时使用相同的名称

Debugging 为什么elixir调试器在调用内置函数而不是我的函数时使用相同的名称,debugging,erlang,elixir,beam,Debugging,Erlang,Elixir,Beam,下面是一个简单的模块,函数中有两个断点,这些断点调用另一个与内置函数名称完全相同的函数:get/1和put/2 defmodule Test do def call_put() do require IEx; IEx.pry put("k", "v") end def call_get() do require IEx; IEx.pry get("k") end def put(_k, _v)do IO.puts("Doing put

下面是一个简单的模块,函数中有两个断点,这些断点调用另一个与内置函数名称完全相同的函数:
get/1
put/2

defmodule Test do
  def call_put() do
    require IEx; IEx.pry
    put("k", "v")
  end
  def call_get() do
    require IEx; IEx.pry
    get("k")
  end

  def put(_k, _v)do
    IO.puts("Doing put")
  end
  def get(_k) do
    IO.puts("Doing get")
  end
end
在shell中执行它:

iex(1)> Test.call_get
Break reached: Test.call_get/0 (lib/test.ex:7)

    5:   end
    6:   def call_get() do
    7:     require IEx; IEx.pry
    8:     get("k")
    9:   end
pry(1)> get("a")
:undefined
pry(2)> Test.get("a")
Doing get
:ok
如图所示,从调试器调用
get/1
会导致执行内置的
get/1
put/2
,而不是执行我的
Test
模块中的函数。
为了正常工作,我需要为我的函数调用命名名称空间。有人能给我解释一下这种行为吗?

这里发生的事情是:环境不同。看:

iex|1 ▶ defmodule Test do
...|1 ▶   def get(p), do: p                            
...|1 ▶   IO.inspect quote do: (def get(), do: get(42))
...|1 ▶ end
{:def, [context: Test, import: Kernel],
 [{:get, [context: Test], []}, [do: {:get, [], '*'}]]}
get/0
函数的AST将包括以下上下文:

{:get, [context: Test], []}

这就是编译器如何知道对非限定函数调用什么。基本上,从同一模块内调用函数的能力是一种语法上的优势。在断点中,模块已经编译,并且肯定无法访问“本地”函数,因为不再存在“本地”函数。您可以
import Test
通过函数的非限定名称访问函数

这里发生的事情是:上下文不同。看:

iex|1 ▶ defmodule Test do
...|1 ▶   def get(p), do: p                            
...|1 ▶   IO.inspect quote do: (def get(), do: get(42))
...|1 ▶ end
{:def, [context: Test, import: Kernel],
 [{:get, [context: Test], []}, [do: {:get, [], '*'}]]}
get/0
函数的AST将包括以下上下文:

{:get, [context: Test], []}

这就是编译器如何知道对非限定函数调用什么。基本上,从同一模块内调用函数的能力是一种语法上的优势。在断点中,模块已经编译,并且肯定无法访问“本地”函数,因为不再存在“本地”函数。您可以
import Test
通过函数的非限定名称访问函数

我认为当前模块的功能不会在
IEx.pry
会话中自动“导入”。您可以在会话启动时执行
import Test
。我认为当前模块的功能不会在
IEx.pry
会话中自动“导入”。你可以在会话启动时进行导入测试。我不认为“从同一个模块中调用函数的能力”是“语法糖”,因为这两件事的行为是不一样的。请参见此处解释的完全限定函数调用与常规调用:。当我从内部运行
quote do:(def get(),do:get(42))
时,我也会得到完全相同的AST,就像您所做的那样,如果我从iex会话运行它,OP的代码就会启动,因此我认为这不是本地调用不起作用的原因。如果我在一个全新的
iex
会话中运行代码,我确实会得到一个
context:Elixir
的AST。我不认为“从同一模块中调用函数的能力”是“语法糖”,因为这两种东西的行为是不一样的。请参见此处解释的完全限定函数调用与常规调用:。当我从内部运行
quote do:(def get(),do:get(42))
时,我也会得到完全相同的AST,就像您所做的那样,如果我从iex会话运行它,OP的代码就会启动,因此我认为这不是本地调用不起作用的原因。如果我在全新的
iex
会话中运行代码,我确实会得到一个带有
context:Elixir
的AST。