在编译时运行任意代码

Lye*_*ish 3 compile-time crystal-lang

我知道Crystal有一个用于在编译时定义代码的宏系统,但除此之外是否可以运行代码?

例如,我们可以这样做,以便它在编译期间运行吗?

puts "foobar"
Run Code Online (Sandbox Code Playgroud)

或者对于一个更严肃的例子,我们可以读取和写入运行编译器的文件系统吗?

Jon*_*Haß 6

我们可以!在运行宏方法系统宏方法的帮助下.

让我们有一个例子,每次构建时都会将随机问候语编译到程序中:

greetings.txt:

Hello
Hey
Hi
Run Code Online (Sandbox Code Playgroud)

greeting.cr:

puts File.read_lines("#{__DIR__}/greetings.txt").sample
Run Code Online (Sandbox Code Playgroud)

greeter.cr:

puts {{run("./greeting").stringify}}
Run Code Online (Sandbox Code Playgroud)

编译时crystal build greeter.cr,您会注意到编译后的二进制文件的输出保持不变,但每次重新编译它时都是随机的.

  • 谢谢,这确实可以解决问题.有点困惑,因为我在编译时(或根本没有)从`greeting.cr`中的代码得到任何`puts`输出,但我会修改一下并阅读你给的链接. (3认同)
  • 啊啊,我明白了.它返回最终语句的结果而不是输出.有意义,完美运作.再次感谢! (2认同)

ast*_*ite 5

作为Jonne所说的额外答案,您可以在编译时使用puts输出内容,但在宏内部.例如:

{{ puts "foobar" }}

您会注意到编译期间会打印"foobar",但可执行文件不执行任何操作(尝试使用crystal build foo.cr; ./foo)

当然,只是在编译时输出一些东西并不是很有用,但是当你想快速调试一些宏时它很有用.

puts宏方法记录在这里:http://crystal-lang.org/api/Macros.html#puts%28expression%29%3ANop-instance-method

  • `{{debug()}}`宏非常适合调试宏.它打印生成的晶体代码.`{{puts}}`可用于在编译时将消息输出给开发人员(例如:弃用消息). (4认同)