在宏中生成长生不老药结构的正确方法
Right way to produce elixir struct in macro
我有以下设计模式:我有一个长生不老药模块,响应 growing/changing 数量的 functions/0
,称为 Defaults
.我还有 CustomConfig
模块,它基本上是结构,派生默认值并假设像这样实例化:
%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
虽然这工作正常,但我很确定,应该有更多 straightforward/elegant/less-cumbersome 方法来实现此功能。
所以我的问题是:如何在不围绕 map-reduce 跳舞的情况下从 Map
声明 defstruct
?
您的代码中有很多实际上不需要的间接访问。示例:
:"#{k}"
可能只是 k
因为 k
已经是一个原子
- 您不需要
Dict.keys/1
因为您可以在循环内的键上进行模式匹配
- 您不需要地图,因为您可以 return 直接从 Enum.map(或从理解)
中获取列表
- 您不需要宏,因为您可以将任何表达式传递给
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 的好处之一是您可以 write assertive code。如果你利用它,你将对你的代码越来越有信心。
我有以下设计模式:我有一个长生不老药模块,响应 growing/changing 数量的 functions/0
,称为 Defaults
.我还有 CustomConfig
模块,它基本上是结构,派生默认值并假设像这样实例化:
%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
虽然这工作正常,但我很确定,应该有更多 straightforward/elegant/less-cumbersome 方法来实现此功能。
所以我的问题是:如何在不围绕 map-reduce 跳舞的情况下从 Map
声明 defstruct
?
您的代码中有很多实际上不需要的间接访问。示例:
:"#{k}"
可能只是k
因为k
已经是一个原子- 您不需要
Dict.keys/1
因为您可以在循环内的键上进行模式匹配 - 您不需要地图,因为您可以 return 直接从 Enum.map(或从理解) 中获取列表
- 您不需要宏,因为您可以将任何表达式传递给
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 的好处之一是您可以 write assertive code。如果你利用它,你将对你的代码越来越有信心。