多方法

注意: 从Nim 0.20开始,要使用多方法,必须在编译时明确传递 —multimethods:on

程序总是使用静态调度。多方法使用动态调度。 要使动态分派处理对象,它应该是引用类型。

  1. type
  2. Expression = ref object of RootObj ## abstract base class for an expression
  3. Literal = ref object of Expression
  4. x: int
  5. PlusExpr = ref object of Expression
  6. a, b: Expression
  7.  
  8. method eval(e: Expression): int {.base.} =
  9. # 重写 base 方法
  10. raise newException(CatchableError, "Method without implementation override")
  11.  
  12. method eval(e: Literal): int = return e.x
  13.  
  14. method eval(e: PlusExpr): int =
  15. # 当心: 依赖动态绑定
  16. result = eval(e.a) + eval(e.b)
  17.  
  18. proc newLit(x: int): Literal =
  19. new(result)
  20. result.x = x
  21.  
  22. proc newPlus(a, b: Expression): PlusExpr =
  23. new(result)
  24. result.a = a
  25. result.b = b
  26.  
  27. echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))

在示例中,构造函数 newLitnewPlus 是procs因为它们应该使用静态绑定,但 eval 是一种方法,因为它需要动态绑定。

从示例中可以看出,基本方法必须使用 base 编译指示进行注释。 base 编译指示还可以提醒程序员使用基本方法 m 作为基础来确定调用 m 可能导致的所有效果。

注意: 编译期执行不支持方法。

注意: 从Nim 0.20开始,不推荐使用泛型方法。

通过procCall禁止动态方法解析

可以通过内置的 system.procCall 来禁止动态方法解析。 这有点类似于传统OOP语言提供的 super 关键字。

  1. type
  2. Thing = ref object of RootObj
  3. Unit = ref object of Thing
  4. x: int
  5.  
  6. method m(a: Thing) {.base.} =
  7. echo "base"
  8.  
  9. method m(a: Unit) =
  10. # Call the base method:
  11. procCall m(Thing(a))
  12. echo "1"