定制注解

可以定制带类型的编译指示。定制的编译指示不会直接影响代码生成,但宏可以检测到它们的存在。给模板加上 pragma 编译指示就能定义定制的编译指示:

  1. template dbTable(name: string, table_space: string = "") {.pragma.}
  2. template dbKey(name: string = "", primary_key: bool = false) {.pragma.}
  3. template dbForeignKey(t: typedesc) {.pragma.}
  4. template dbIgnore {.pragma.}

考查这个有风格的例子,它是关于对象关系映射 (ORM) 的一个合理实现:

  1. const tblspace {.strdefine.} = "dev" # 控制开发、测试、生成环境的开关
  2. type
  3. User {.dbTable("users", tblspace).} = object
  4. id {.dbKey(primary_key = true).}: int
  5. name {.dbKey"full_name".}: string
  6. is_cached {.dbIgnore.}: bool
  7. age: int
  8. UserProfile {.dbTable("profiles", tblspace).} = object
  9. id {.dbKey(primary_key = true).}: int
  10. user_id {.dbForeignKey: User.}: int
  11. read_access: bool
  12. write_access: bool
  13. admin_access: bool

在本例中,通过定制的编译指示来描述 Nim 对象如何被映射到关系数据库的模式中。定制的编译指示可以有零个或多个参数。请使用模板调用语法来传递多个参数。 所有的参数都有类型,并且遵循模板的标准重载解析规则。因此,可以为参数设置默认值,可以通过名称传递,可以使用可变参数,等等。

所有可以使用普通编译指示的地方,都可以使用定制的编译指示,为过程、模板、类型和变量定义、语句等添加注解。

宏模块包含工具,可以用来简化自定义编译指示的访问 hasCustomPragma , getCustomPragmaVal 。 详情参阅模块文档。这些宏并不神奇,它们也可以通过逐步的对象表示的 AST 来实现。

带有自定义指示的更多示例:

  • 更好的序列化/反序列化控制:

    1. type MyObj = object
    2. a {.dontSerialize.}: int
    3. b {.defaultDeserialize: 5.}: int
    4. c {.serializationKey: "_c".}: string
  • 在游戏引擎中为 gui 查看器添加类型:

    1. type MyComponent = object
    2. position {.editable, animatable.}: Vector3
    3. alpha {.editRange: [0.0..1.0], animatable.}: float32