網友@沉沒捕魚,贊助了一臺伺服器
這個系列的教程寫完之後,我們就要開始著手搭建Nim的社群了~
異常
Nim中的異常型別是物件型別
根據慣例,Nim中的異常型別的命名都應該以Error字尾結尾
在system模組中定義了異常型別的基類
所有的異常都應該派生自system.Exception型別
由於我們不清楚異常物件的生命週期,
所以必須在記憶體堆上為異常的例項分配空間
編譯器不允許開發人員在棧上為異常分配空間
你如果想丟擲一個異常,你必須為這個異常的msg屬性賦值
按照約定,只有在非常特殊的情況下才應該引發異常
打個比方:你不應該為打不開一個檔案而引發異常,
因為這個檔案有可能是不存在的。
raise語句引發異常
你可以使用raise語句引發一個異常
請看下面的程式碼
var e: ref OSError new(e) e.msg = "the request to the OS failed" raise e
如果raise關鍵字後面美元后跟著一個異常的例項
那麼將再次引發最後一個異常
system模組中還為我們定義了一個newException的方法
請看如下程式碼:(是不是簡化了很多呢)
raise newException(OSError, "the request to the OS failed")
try語句捕獲異常
可以用try語句捕獲異常
# read the first two lines of a text file that should contain numbers # and tries to add them var f: File if open(f, "numbers.txt"): try: let a = readLine(f) let b = readLine(f) echo "sum: ", parseInt(a) + parseInt(b) except OverflowError: echo "overflow!" except ValueError: echo "could not convert string to integer" except IOError: echo "IO error!" except: echo "Unknown exception!" # reraise the unknown exception: raise finally: close(f)
如果try程式碼塊中的程式碼,執行的時候引發了一個異常
那麼就會執行相應的except語句
如果後面的except語句沒有明確列出這個異常
那麼就會後自行最後一個空except語句
這看起來類似if else語句
如果存在finally語句,
那finally語句塊內的程式碼無論如何都會被執行的
如果一個異常沒有得到處理
那麼這個異常會從堆疊向上傳播
這就意味著,呼叫鏈上的方法有可能不會被執行
(如果他被執行了,那麼他一定在一個finally子句中)
如果你需要訪問異常物件
可以使用system模組中的getCurrentException方法或者getCurrentExceptionMsg方法
來看下面的示例程式碼
try: doSomethingHere() except: let e = getCurrentException() msg = getCurrentExceptionMsg() echo "Got exception ", repr(e), " with message ", msg
在方法上做關於異常的註解
如果你用{.raises.}對某一個方法進行了註解
那麼在編譯期就會檢測這個方法(或這個方法所呼叫到的方法)會不會丟擲了某個異常
如果會,則編譯不通過
示例程式碼如下:
proc complexProc() {.raises: [IOError, ArithmeticError].} = ... proc simpleProc() {.raises: [].} = ...
這一段我也沒怎麼看明白,大家自己看原文吧先
泛型
Nim語言的方法引數化、迭代器、等特性都是靠語言本身的泛型特性實現的
這個特性對於強型別容器是非常有用的
來看一下程式碼
type BinaryTreeObj[T] = object # BinaryTree is a generic type with # with generic param ``T`` le, ri: BinaryTree[T] # left and right subtrees; may be nil data: T # the data stored in a node BinaryTree*[T] = ref BinaryTreeObj[T] # type that is exported proc newNode*[T](data: T): BinaryTree[T] = # constructor for a node new(result) result.data = data proc add*[T](root: var BinaryTree[T], n: BinaryTree[T]) = # insert a node into the tree if root == nil: root = n else: var it = root while it != nil: # compare the data items; uses the generic ``cmp`` proc # that works for any type that has a ``==`` and ``<`` operator var c = cmp(it.data, n.data) if c < 0: if it.le == nil: it.le = n return it = it.le else: if it.ri == nil: it.ri = n return it = it.ri proc add*[T](root: var BinaryTree[T], data: T) = # convenience proc: add(root, newNode(data)) iterator preorder*[T](root: BinaryTree[T]): T = # Preorder traversal of a binary tree. # Since recursive iterators are not yet implemented, # this uses an explicit stack (which is more efficient anyway): var stack: seq[BinaryTree[T]] = @[root] while stack.len > 0: var n = stack.pop() while n != nil: yield n.data add(stack, n.ri) # push right subtree onto the stack n = n.le # and follow the left pointer var root: BinaryTree[string] # instantiate a BinaryTree with ``string`` add(root, newNode("hello")) # instantiates ``newNode`` and ``add`` add(root, "world") # instantiates the second ``add`` proc for str in preorder(root): stdout.writeln(str)
上面的示例展示了一個泛型二叉樹
通過這個例子,您可以看到,可以用方括號來完成方法的泛型化、泛型迭代器等特性