繁体   English   中英

在宏中生成长生不老药结构的正确方法

[英]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

您的代码中有很多真正不需要的间接方式。 例子:

  1. :"#{k}"可能只是k因为k已经是原子
  2. 您不需要Dict.keys/1因为您可以在循环内的键上进行模式匹配
  3. 您不需要地图,因为您可以直接从Enum.map(或理解)返回列表。
  4. 您不需要宏,因为您可以将任何表达式传递给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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM