我发现这段代码产生了意想不到的结果:
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
答案 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.