宏是一些预编译的方法(在编译时被加入到抽像语法树中),这些方法必须是完整有效的Crystal代码。

  1. macro define_method(name, content)
  2. def {{name}}
  3. {{content}}
  4. end
  5. end
  6. # This generates:
  7. #
  8. # def foo
  9. # 1
  10. # end
  11. define_method foo, 1
  12. foo #=> 1

宏作用域

宏被定义在顶层作用域,所有代码中都可用。如果某个宏被标记为private 那么它只在当前文件中可见。宏也可以定义在类和模块中, 并且在定义它的作用域中可见。程序也会在先祖域中搜索宏(父类 及被包含的模块中)。For example, a block which is given an object to use as the default receiver by being invoked with with … yield can access macros defined within that object’s ancestors chain:

  1. class Foo
  2. macro emphasize(value)
  3. "***#{ {{value}} }***"
  4. end
  5. def yield_with_self
  6. with self yield
  7. end
  8. end
  9. Foo.new.yield_with_self { emphasize(10) } #=> "***10***"

定义在类中或模块中的宏 也可以在外部被调用。

  1. class Foo
  2. macro emphasize(value)
  3. "***#{ {{value}} }***"
  4. end
  5. end
  6. Foo.emphasize(10) # => "***10***"

插值

使用 {{…}} 在语法树中进行插入值。

宏调用

你可以在编译时调用一些方法, 这些方法被定义在Crystal::Macros 模块中。

条件语句

  1. # 你可以使用{% if condition %} ... {% end %} 来按条件生成代码。宏的条件语句可以在宏定义之外的地方使用。
  2. macro define_method(name, content)
  3. def {{name}}
  4. {% if content == 1 %}
  5. "one"
  6. {% else %}
  7. {{content}}
  8. {% end %}
  9. end
  10. end
  11. define_method foo, 1
  12. define_method bar, 2
  13. foo #=> one
  14. bar #=> 2

迭代

迭代语句也可以在宏定义之外的地方使用。

  1. macro define_dummy_methods(names)
  2. {% for name, index in names %}
  3. def {{name.id}}
  4. {{index}}
  5. end
  6. {% end %}
  7. end
  8. define_dummy_methods [foo, bar, baz]
  9. foo #=> 0
  10. bar #=> 1
  11. baz #=> 2
  12. #
  13. macro define_dummy_methods(hash)
  14. {% for key, value in hash %}
  15. def {{key.id}}
  16. {{value}}
  17. end
  18. {% end %}
  19. end
  20. define_dummy_methods({foo: 10, bar: 20})
  21. foo #=> 10
  22. bar #=> 20
  23. #
  24. {% for name, index in ["foo", "bar", "baz"] %}
  25. def {{name.id}}
  26. {{index}}
  27. end
  28. {% end %}
  29. foo #=> 0
  30. bar #=> 1
  31. baz #=> 2

宏方法定义

todo

钩子

在一些场景下,一些特殊的宏被当成钩子来使用。这些场景是 inherited, included, extended 和 method_missing

  1. 1.inherited在编译时被触发,如果定义了子类。@type is the inheriting type.
  2. 2.included在编译时被触发,当一个模块被include时。@type is the including type.
  3. 3.extended在编译时被触发,当一个模块被extend时。@type is the extending type.
  4. 4.method_missing 在编译时被触发,当方法不存在时.
  5. 例子: inherited
  6. class Parent
  7. macro inherited
  8. def lineage
  9. "{{@type.name.id}} < Parent"
  10. end
  11. end
  12. end
  13. class Child < Parent
  14. end
  15. Child.new.lineage #=> "Child < Parent"

例子: method_missing

  1. macro method_missing(call)
  2. print "Got ", {{call.name.id.stringify}}, " with ", {{call.args.size}}, " arguments", '\n'
  3. end
  4. foo # Prints: Got foo with 0 arguments
  5. bar 'a', 'b' # Prints: Got bar with 2 arguments

变量刷新

//todo