nim的引用和指標

xland發表於2015-08-28

nim語言的引用和其他語言的指標有點相似

可以提供一種“多對一”的關係

這就意味著不同的引用可以指向同一個記憶體位置

 

nim區分可被追蹤的引用和不可被追蹤的引用

不可被追蹤的引用又稱為指標

可被追蹤的引用可以被垃圾回收器回收

不可被追蹤的引用指向手動分配的物件,或其他地方建立出來的一塊記憶體區域

這也就是說,不可被追蹤的引用是不安全的

對於某些底層操作,不可被追蹤的引用有其存在的必要

 

可被追蹤的引用使用ref關鍵字定義,

不可被追蹤的引用使用ptr關鍵字定義

 

空下標的方括號[]可以用來解引用

addr方法可以返回一個例項的地址

對於一個地址來說,它始終是一個不可追蹤的引用

所以addr方法也是一個不安全的方法。

 

.操作符和[]操作符可以隱式執行,先來看一下下面的程式碼

type
  Node = ref NodeObj
  NodeObj = object
    le, ri: Node
    data: int

var
  n: Node
new(n)
n.data = 9

在上面的程式碼中,不需要寫成n[].data,

因為方括號操作符已經隱式執行了

事實上nim官方也強烈不建議寫成n[].data

 

另外,自動解引用操作也直接作用於一個方法的呼叫

但目前看來,還必須加上{.experimental.}配置節

請看如下示例程式碼:

{.experimental.}
proc depth(x: NodeObj): int = ...
var
  n: Node
new(n)
echo n.depth

也不用寫成n[].depth

 

為了簡化型別檢查,nim語言不支援遞迴元組

下面的寫法是錯誤的

type MyTuple = tuple[a: ref MyTuple]

同樣 T = ref T 也是錯誤的

 

如果一個物件只能出現其引用型別,不能出現其值型別

那麼可以用如下方法完成:

type
  Node = ref object
    le, ri: Node
    data: int

 

可以使用內建的new方法為一個可被追蹤的物件分配記憶體

可以使用alloc、dealloc和realloc來應對不可被追蹤的物件

這些方法的具體資訊都可以在system類庫的說明文件中找到

 

如果一個引用指向為空,那麼這個引用的值就是nil

 

如果你碰到一個不可被追蹤的物件裡面包含一個可被追蹤的物件(或者是一個字串、又或者是一個sequences)

那麼就需要特別留意了,為了讓一切都正常釋放,

你必須在釋放不可被追蹤的物件之前,使用內建的GCunref方法處理一下這個物件的那些特殊屬性

請看下面的示例程式碼:

type
  Data = tuple[x, y: int, s: string]
# 在記憶體堆上建立一個不可被追蹤的物件:
var d = cast[ptr Data](alloc0(sizeof(Data)))
# create a new string on the garbage collected heap:
d.s = "abc"
# 告訴 GC 這個string型別的屬性已經沒有存在的必要了:
GCunref(d.s)
# 釋放不可被追蹤的物件:
dealloc(d)

如果不用GCunref方法處理一下物件的字串屬性,

那麼這個字串所佔用的記憶體將永遠不會被釋放

上面的程式碼同時也展示了:

怎麼獲得一個型別的size

alloc0方法建立一個沒有型別的指標

cast方法可以繞過型別系統,讓指標具有型別ptr Data

只有在非常必要的時候再用cast方法,因為他會破壞型別安全,導致不可預知的BUG

 

 

 

 


相關文章