Nim 語言程式教學:例外 (Exception) 處理

PUBLISHED ON APR 15, 2018 — PROGRAMMING

即使程式碼本身正確無誤,我們仍然要面對程式運行時可能發生的錯誤,像是網路無法連線、檔案或資料夾權限不足、檔案格式錯誤、命令列參數錯誤、除以零等運算錯誤等。在實務上,我們不能一廂情願地認定程式不會發生錯誤,而要撰寫相對應的程式碼來處理錯誤。

在程式語言中,錯誤處理 (exception handling) 分為兩類,像 C 等比較老派的語言沒有內建錯誤處理的語法,通常就是直接使用 if 等控制流程來控制錯誤發生時程式運作的過程;現代語言大部分都會使用 try ... catch ... 或同義的語法來處理錯誤。基本上,錯誤處理算是另一種控制流程,只是這套流程僅用於錯誤或例外發生時。本文介紹 Nim 的例外處理。

在 Nim 語言中,將例外 (Exception) 包裝成物件,可到這裡觀看其例外物件的階層。引發例外的方式是用 raise 呼叫例外物件,如以下短例:

raise newException(Exception, "Something wrong")

執行此程式會得到以下結果:

$ ./raise
raise.nim(1)             raise
Error: unhandled exception: Something wrong [Exception]

當例外物件引發時,若沒有進一步處理該物件,預設情形下會導致程式從例外物件所在處中止程式。有時候這樣的處理方式不是我們想要的,Nim 提供 try ... except ... finally 區塊,讓程式設計者可以決定錯誤發生時程式如何運作。如以下短例:

proc doSomething() =
  raise newException(Exception, "Something wrong")

try:
  doSomething()
except:
  echo "The program ended unexpectedly"

執行此程式會得到以下結果:

$ ./try
The program ended unexpectedly

比較這兩個例子可以看出,例外發生時是否有人為介入會有不同的效果。如果撰寫函式庫,使用的對象是程式設計者,必要時直接拋出例外倒無可厚非,但在撰寫應用程式時,直接拋出例外會讓使用者以為程式發生什麼臭蟲,一些早期的 Java 程式沒有考慮周詳可能的例外時,就會噴出一長串讓人難以理解的例外訊息。對於應用程式來說,將例外進行進一步處理,而不是突然結束,對使用者來說較為友善。

對於外部資源輸出入,可使用 defer 語法,讓程式碼看起來更簡潔,這是向 Go 語言致敬的語法。實例如下:

var f = open("numbers.txt")
defer: close(f)

f.write   "abc"
f.write   "def"

上例和以下的範例同義:

var f = open("numbers.txt")

try:
  f.write   "abc"
  f.write   "def"
finally:
  close(f)

讀者可從中自行選擇喜歡的語法。