[英]Right way to produce elixir struct in macro
我有以下设计模式:我有一个长生不老药模块,它响应functions/0
增加/更改量,称为Defaults
。 我还有CustomConfig
模块,它基本上是struct,派生默认值并假定要实例化,例如:
%CustomConfig{ foo: "bar" }
如果初始化属性被覆盖,则其他属性将从“ Defaults
中获取,而那些在“ Defaults
中不具有相同名称的函数将被拒绝。 到现在为止还挺好。
为了独立于内容( Defaults
中的功能列表)实现此行为,我使用了一个宏(在另一个模块中,因为一个人不能使用在结构声明中在同一模块中定义的宏):
defmacro define_struct_with_defaults do
quote do
defstruct Map.to_list(
quote do: unquote(Enum.reduce(Dict.keys(
Defaults.__info__(:functions)), %{}, fn(k, acc) ->
Map.put(acc, :"#{k}", apply(Defaults, :"#{k}", []))
end)))
end
end
虽然这很好用,但我可以肯定,应该有更简单/优雅/更少麻烦的方法来实现此功能。
因此,我的问题是: 如何在不围绕map-reduce跳舞的情况下从Map
声明defstruct
?
您的代码中有很多真正不需要的间接方式。 例子:
:"#{k}"
可能只是k
因为k
已经是原子 Dict.keys/1
因为您可以在循环内的键上进行模式匹配 defstruct
这是重写代码的方法:
defmodule Default do
def foo, do: 1
def bar, do: 2
end
defmodule Config do
data =
# Get all functions with 0 arity and the respective default
for {k, 0} <- Default.__info__(:functions) do
{k, apply(Default, k, [])}
end
defstruct data
end
Elixir的好处之一是您可以编写断言代码 。 如果您利用它,您将对代码越来越有信心。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.