錯誤處理系統
主要使用Result類型 在Erg中,如果您丟棄Error類型的對象(頂層不支持),則會發生錯誤
異常,與 Python 互操作
Erg沒有異常機制(Exception)。導入Python函數時
- 將返回值設置為
T 或 Error
類型 T or Panic
類型(可能導致運行時錯誤)
有兩個選項,pyimport
默認為后者。如果要作為前者導入,請使用
在pyimport
exception_type
中指定Error
(exception_type: {Error, Panic}
)
異常和結果類型
Result
類型表示可能是錯誤的值。Result
的錯誤處理在幾個方面優于異常機制
首先,從類型定義中可以看出子程序可能會報錯,實際使用時也很明顯
# Python
try:
x = foo().bar()
y = baz()
qux()
except e:
print(e)
在上面的示例中,僅憑此代碼無法判斷哪個函數引發了異常。即使回到函數定義,也很難判斷函數是否拋出異常
# Erg
try!:
do!:
x = foo!()?.bar()
y = baz!()
qux!()?
e =>
print! e
另一方面,在這個例子中,我們可以看到foo!
和qux!
會引發錯誤
確切地說,y
也可能是Result
類型,但您最終必須處理它才能使用里面的值
使用 Result
類型的好處不止于此。Result
類型也是線程安全的。這意味著錯誤信息可以(輕松)在并行執行之間傳遞
語境
由于Error
/Result
類型本身不會產生副作用,不像異常,它不能有發送位置(Context)等信息,但是如果使用.context
方法,可以將信息放在錯誤
對象。可以添加。.context
方法是一種使用Error
對象本身并創建新的 Error
對象的方法。它們是可鏈接的,并且可以包含多個上下文
f() =
todo() \
.context "to be implemented in ver 1.2" \
.context "and more hints ..."
f()
# Error: not implemented yet
# hint: to be implemented in ver 1.2
# hint: and more hints ...
請注意,諸如 .msg
和 .kind
之類的 Error
屬性不是次要的,因此它們不是上下文,并且不能像最初創建時那樣被覆蓋
堆棧跟蹤
Result
類型由于其方便性在其他語言中經常使用,但與異常機制相比,它的缺點是難以理解錯誤的來源
因此,在 Erg 中,Error
對象具有名為 .stack
的屬性,并再現了類似偽異常機制的堆棧跟蹤
.stack
是調用者對象的數組。每次 Error 對象被return
(包括通過?
)時,它都會將它的調用子例程推送到.stack
如果它是 ?
ed 或 .unwrap
ed 在一個不可能 return
的上下文中,它會因為回溯而恐慌
f x =
...
y = foo.try_some(x)?
...
g x =
y = f(x)?
...
i = g(1)?
# Traceback (most recent call first):
# ...
# Foo.try_some, line 10, file "foo.er"
# 10 | y = foo.try_some(x)?
# module::f, line 23, file "foo.er"
# 23 | y = f(x)?
# module::g, line 40, file "foo.er"
# 40 | i = g(1)?
# Error: ...
恐慌
Erg 還有一種處理不可恢復錯誤的機制,稱為 panicing 不可恢復的錯誤是由外部因素引起的錯誤,例如軟件/硬件故障、嚴重到無法繼續執行代碼的錯誤或程序員未預料到的錯誤。等如果發生這種情況,程序將立即終止,因為程序員的努力無法恢復正常運行。這被稱為"恐慌"
恐慌是通過 panic
功能完成的
panic "something went wrong!"