• 引用和指针类型

    引用和指针类型

    引用(类似于其他编程语言中的指针)是引入多对一关系的一种方式。 这意味着不同的引用可以指向并修改内存中的相同位置(也称为 别名 )。

    Nim区分 追踪和 未追踪 引用。 未追踪引用也叫 指针 。 追踪引用指向垃圾回收堆中的对象,未追踪引用指向手动分配对象或内存中其它位置的对象。 因此,未追踪引用是 不安全 的。 然而,对于某些低级操作(访问硬件),未追踪引用是不可避免的。

    使用 ref 关键字声明追踪引用,使用 ptr 关键字声明未追踪引用。 通常,ptr T 可以隐式转换为 pointer 类型。

    空的下标 [] 表示法可以用来取代引用, addr 程序返回一个对象的地址。 地址始终是未经过引用的参考。 因此, addr 的使用是 不安全的 功能。

    . (访问元组和对象字段运算符)和 [] (数组/字符串/序列索引运算符)运算符对引用类型执行隐式解引用操作:

    1. type
    2. Node = ref NodeObj
    3. NodeObj = object
    4. le, ri: Node
    5. data: int
    6.  
    7. var
    8. n: Node
    9. new(n)
    10. n.data = 9
    11. # 不必写n[].data; 实际上 n[].data是不推荐的!

    还对过程调用的第一个参数执行自动解引用。 但是目前这个功能只能通过 {.experimental:"implicitDeref".} 来启用:

    1. {.experimental: "implicitDeref".}
    2.  
    3. proc depth(x: NodeObj): int = ...
    4.  
    5. var
    6. n: Node
    7. new(n)
    8. echo n.depth
    9. # 也不必写n[].depth

    为了简化结构类型检查,递归元组无效:

    1. # 无效递归
    2. type MyTuple = tuple[a: ref MyTuple]

    同样, T = ref T 是无效类型。

    作为语法扩展 object 类型,如果在类型部分中通过 ref objectptr object 符号声明,则可以是匿名的。 如果对象只应获取引用语义,则此功能非常有用:

    1. type
    2. Node = ref object
    3. le, ri: Node
    4. data: int

    要分配新的追踪对象,必须使用内置过程 new 。 为了处理未追踪的内存,可以使用过程 allocdeallocrealloc 。 系统模块的文档包含更多信息。

    Nil —-

    如果引用指向 nothing ,则它具有值 nilnil 也是所有 refptr 类型的默认值。 解除引用 nil 是一个不可恢复的致命运行时错误。 解除引用操作 p [] 意味着 p 不是nil。 这可以通过实现来利用,以优化代码,如:

    1. p[].field = 3
    2. if p != nil:
    3. # 如果p为nil,``p []`` 会导致崩溃,
    4. # 所以我们知道 ``p`` 总不是nil。
    5. action()

    Into:

    1. p[].field = 3
    2. action()

    注意 :这与用于解引用NULL指针的C的“未定义行为”不具有可比性。