当我在Elixir的嵌套模块中使用模块名称时,谁可以解释奇怪的结果?

时间:2016-10-15 15:09:31

标签: elixir

我发现这段代码产生了意想不到的结果:

defmodule Foo do
  defmodule Foo.Bar do
    def test1 do
      IO.inspect Foo.Baz
    end
    def test2 do
      IO.inspect Other.Baz
    end
  end
end
> Foo.Foo.Bar.test1
Foo.Foo.Baz
> Foo.Foo.Bar.test2
Other.Baz

我希望测试至少应该产生一致的结果,例如:

# Both have a namespace of Foo
> Foo.Foo.Bar.test1
Foo.Foo.Baz
> Foo.Foo.Bar.test2
Foo.Other.Baz
# or
# Neither has a namespace of Foo
> Foo.Foo.Bar.test1
Foo.Baz
> Foo.Foo.Bar.test2
Other.Baz

但是意外的结果显示它依赖于模块名称的前缀({1}}和Foo.Bar在test1中),这对我来说是令人惊讶的。

更新

由于@mudasobwa

的答案,我意识到还有另一个问题

对于这种情况,我们知道Foo.Baz应为B因为我们想直接使用A.B

B

但为此,为什么defmodule A do defmodule B do def test do IO.inspect B end end end > A.B.test A.B 仍为B

A.B

1 个答案:

答案 0 :(得分:2)

Both Foo.Baz and Other.Baz are atoms. Just simple atoms and the ability to write them with fancy dots and capitalized is nothing but the syntactic sugar. Try to open IEx and loading nothing just type:

iex(1)> i Foo.Baz

the result would be: IEx is aware of it, and it is an atom:

iex(1)> i Foo.Baz

Term
  Foo.Baz
Data type
  Atom
Reference modules
  Atom

That said, you output atoms and they are successfully output. The fact that they look similar to modules’ names is an occasion.


But since this is used as a module name representation, Elixir tries to do it’s best to “resolve” those. Being “inside module,” one might call a module function from inside other module function without prefixing it with module name:

defmodule A do
  def a, do: IO.puts "Hello"
  def b, do: a  # ⇐ this
end

Here a is implicitly resolved to A.a when called from A.b. The same happens for embedded/nested modules:

defmodule A do
  defmodule B do
    def a, do: IO.puts "Hello"
    def b, do: B.a  # ⇐ this
  end
end

To make this B.a call possible, B.a is in fact being resolved to A.B.a, which is possible because B inside itself is resolved to A.B.

What you see is a drawback of this atom to module name extrapolation.