macros - 在宏中定义和使用函数
问题描述
按照这个例子:
defmodule Greetify do
defmacro __using__(_) do
quote do
Module.register_attribute __MODULE__, :greet, accumulate: true,
persist: false
@before_compile Greetify
end
end
defmacro __before_compile__(env) do
greetings = Module.get_attribute(env.module, :greet)
for {name, age} <- greetings do
IO.puts "#{name} is #{age} years old"
end
end
end
是否可以定义在宏中使用的内部函数?
例如:
defmacro __before_compile__(env) do
greetings = Module.get_attribute(env.module, :greet)
say_greetings(greetings)
defp say_greetings(grettings) do
for {name, age} <- greetings do
IO.puts "#{name} is #{age} years old"
end
end
end
尝试这个编译器对函数 say_grettings 的抱怨没有定义
该示例源http://elixir-recipes.github.io/metaprogramming/accumulating-annotations/
解决方案
嗯,这是可能的。您的代码的问题是您混合了范围。Elixir 中的宏正在编译阶段进行扩展。目前没有编译say_greetings/1
函数(除了不能defp
从内部调用之外defmacro
,但这可能会通过适当的引用来克服。)
为此,您需要在与make 可用say_greetings/1
的相同范围内声明。__before_compile__/1
您不能将其定义为函数(见上文),但解决方法是将其也定义为宏。这样它会在编译过程中被扩展,一切都会正常工作(另外,我怀疑我理解这是什么原因。)
总结:
defmodule Greetify do
defmacro __using__(_) do
quote do
Module.register_attribute __MODULE__, :greet, accumulate: true, persist: false
@before_compile Greetify
end
end
defmacrop say_greetings(greetings) do
quote do
for {name, age} <- unquote(greetings) do
IO.puts "#{name} is #{age} years old"
end
end
end
defmacro __before_compile__(env) do
greetings = Module.get_attribute(env.module, :greet)
say_greetings(greetings)
end
end
defmodule Test do
use Greetify
@greet {"Jon", 21}
@greet {"Sam", 23}
end
推荐阅读
- python - 从两个文件读取并写入一个文件
- c - 如何从键盘读取只有 4 个字母数字字符的字符串,不能少一个,不能多一个
- reactjs - 在检查了 render() 中的某些条件后,想要使用 setState 更新状态值,我该怎么做?
- flutter - Flutter 中的 Listview 过滤器搜索
- jena - How to save ontology separately in different files?
- linux - 期望 - telnet 连接
- asp.net - 自定义重定向页面不起作用
- java - 匹配名称相同但子值不同的标签
- asp.net-web-api - asp.net core 2.0中上传文件动作方法
- tcl - How to protect a variable from being overwritten