【在主画面加入捷径】
       
【选择语系】
繁中 简中

Nim 语言程序教学:类 (Class) 和物件 (Object)

【赞助商连结】

    面向对象程序是目前主流的程序设计范式,其思维为在函式上加入状态,藉由状态改变而改变程序内的数据。在本文中,我们从 Nim 语言的观点来看如何撰写面向对象程序。

    建立物件

    在以下例子中,我们建立一个 Point 类,该类带有 xy 两个属性,之后就可以用 Point 类建立 p 物件:

    type
      Point* = ref object
        x*: float
        y*: float
    
    when isMainModule:
      let p = Point(x: 3, y: 4)
      assert(p.x == 3)
      assert(p.y == 4)

    在 Nim 语言中,某个类没有继承其他类时,皆会继承 object 类。在 Point*x*y* 中,尾端带有星号 *,这牵涉到模块的封装;我们会于后文详谈模块,目前只要知道若要对外公开的项目就要加星号 * 即可。

    带有方法的物件

    在上一个例子中,我们将物件的属性直接对外公开,这不是良好的习惯;若以后我们要限制属性的范围,会破坏原有的外部程序代码。一般来说,我们会将属性私有化,用公开方法来存取,如下例:

    type
      Point* = ref object
        px: float
        py: float
    
    proc x*(p: Point): float =
      p.px
    
    proc `x=`(p: Point, x: float) =
      p.px = x
    
    proc y*(p: Point): float =
      p.py
    
    proc `y=`(p: Point, y: float) =
      p.py = y
    
    proc newPoint*(x: float, y: float): Point =
      new(result)
      result.x = x
      result.y = y
    
    when isMainModule:
      var p = newPoint(3, 4)
      assert(p.x == 3)
      assert(p.y == 4)

    这种存取属性的方法,称为 getter 和 setter。在我们这个例子中,x*y* 等 getters 是公开的,但 x=y= 等 setters 是私有的,在物件建立后,我们就无法更改 pxpy 这两个属性;藉由控管公开方法,属性变成唯读的。

    我们可以将上例修改,属性就会变成可修改的:

    type
      Point* = ref object
        px: float
        py: float
    
    proc x*(p: Point): float =
      p.px
    
    proc `x=`*(p: Point, x: float) =
      p.px = x
    
    proc y*(p: Point): float =
      p.py
    
    proc `y=`*(p: Point, y: float) =
      p.py = y
    
    proc newPoint*(x: float, y: float): Point =
      new(result)
      result.x = x
      result.y = y
    
    when isMainModule:
      var p = newPoint(0, 0)
      assert(p.x == 0)
      assert(p.y == 0)
    
      p.x = 3
      p.y = 4
      assert(p.x == 3)
      assert(p.y == 4)

    一旦将属性设为可修改的,日后再将其改为唯读的,就有可能破坏外部程序代码;所以,尽量不要一下子就将权限开放过大。

    UFCS (Uniform Function Call Syntax)

    UFCS 算是 Nim 的语法糖,在这个守则下,method(obj, args) 等同于 obj.method(args)。如下例:

    type
      Point = ref object
        px: float
        py: float
    
    # Declare Point as above.
    
    when isMainModule:
      var p = newPoint(3, 4)
      assert(x(p) == 3) # Same as p.x
      assert(y(p) == 4) # Same as p.y
    【赞助商连结】