我在elixir中有一个属性的模块:
defmodule MyAwesomeModule do
@awesome_number 7
# other stuff...
end
Run Code Online (Sandbox Code Playgroud)
我无法访问@awesome_number模块外部.我尝试过使用该Module.get_attribute/2方法,但它会抛出此错误:
iex(79)> Module.get_attribute(MyAwesomeModule, :awesome_number)
** (ArgumentError) could not call get_attribute on module MyAwesomeModule because it was already compiled
(elixir) lib/module.ex:1101: Module.assert_not_compiled!/2
(elixir) lib/module.ex:1016: Module.get_attribute/3
Run Code Online (Sandbox Code Playgroud)
所以现在,我将模块属性包装在一个方法中来访问它,但它对我来说并没有多大意义.我可以简单地使用该方法并停止一起使用该属性:
defmodule MyAwesomeModule do
@awesome_number 7
def awesome_number, do: @awesome_number
# other stuff...
end
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,有更好/正确的方法吗?
ven*_*laf 19
AFAIK无法访问给定模块之外的模块属性.定义一个公开模块属性的函数是要走的路,就是你正在做的事情.
仍然有充分的理由保留模块属性,而不是仅使用没有模块属性的函数.这取决于具体情况.请记住,存储在模块属性中的值是在编译时计算的.话虽如此,您可能有不同的理由使用或不使用模块属性.我们来看下面的例子:
如果awesome_number每次访问时必须随机生成,则必须使用函数.
如果awesome_number需要计算(长时间)并且不必更改其值,那么使用模块属性+函数来公开它,就是要走的路.
编辑:
我之前说过的模块属性还有很多.它们的功能优于功能.以下是elixir文档的示例和引用:
defmodule MyServer do
@my_data 14
def first_data, do: @my_data
@my_data 13
def second_data, do: @my_data
end
MyServer.first_data #=> 14
MyServer.second_data #=> 13
Run Code Online (Sandbox Code Playgroud)
请注意,读取函数内的属性会获取其当前值的快照.换句话说,该值在编译时读取,而不是在运行时读取.正如我们将要看到的,这使得属性可用于在模块编译期间用作存储.
将它们与Module.register_attribute/3(https://hexdocs.pm/elixir/Module.html#register_attribute/3)一起使用,尤其是accumulate: true选项,使它们在更多方面有用.
我想说的是,它们比仅仅用作常量更有用.
Dav*_*rsa 10
有一种通过使用use和宏来"欺骗"的方法.看看这个例子.
例如,假设您将模块定义为:
defmodule AwesomeLibrary do
defmacro __using__(_) do
quote do
def print(s), do: IO.puts(s)
end
end
end
Run Code Online (Sandbox Code Playgroud)
然后,在某些模块中,您可以通过use这种方式使用关键字.
defmodule TestLibrary do
use AwesomeLibrary
end
Run Code Online (Sandbox Code Playgroud)
结果是__using__块中定义的所有内容都在编译时复制到新模块中.因此,在这种情况下,TestLibrary.print即使print在另一个模块中定义,也可以使用.
这也用于复制常量.作为示例,您可以查看TimeX库.它使用专用模块来处理需要时导入的常量.
在我看来,这是在大型代码库中共享常量定义的更好方法.