3 回答

TA貢獻1796條經驗 獲得超4個贊
多次返回不是Go唯一的,并且不能替代異常。用C(或C ++)術語來說,它們是返回包含多個值的結構(對象)的簡潔且用戶友好的替代方法。
如果您僅此意思,它們確實提供了指示錯誤的便捷方法。
為什么將“資產”視為替代品?
斷言最初用于調試。他們在程序處于“不可能”狀態的情況下暫停了該程序,設計認為這種情況不應該發生,但是無論如何還是會發生。返回錯誤不太可能有太大幫助。代碼庫顯然還無法正常工作,那么到底如何才能成功恢復呢?當有一個需要引起注意的錯誤時,您為什么還要這么做?
在生產代碼中使用斷言有些不同-顯然存在性能和代碼大小方面的顧慮,因此通常的方法是在代碼分析和測試確信您“不可能”的情況確實不可能時,將它們刪除。但是,如果您正在以這種偏執級別運行代碼,它正在對自身進行審核,那么您還可能會偏執于:如果讓代碼繼續在“不可能”狀態下運行,那么它可能會做一些危險的事情:破壞有價值的數據,從而超出了堆棧分配的范圍,并可能創建安全漏洞。同樣,您只想盡快關閉。
您斷言的內容確實與您使用異常的內容不同:當C ++和Java之類的編程語言為“不可能”的情況(logic_error
,ArrayOutOfBoundsException
)提供異常時,它們無意間鼓勵一些程序員認為他們的程序應該嘗試從真正無法控制的情況中恢復過來。有時這是適當的,但是出于充分的原因,這里有Java建議不要捕獲RuntimeExceptions。偶爾捕獲一個是一個好主意,這就是它們存在的原因。捕獲它們幾乎總是一個好主意,這意味著它們無論如何都等于暫停了程序(或至少是線程)。

TA貢獻1854條經驗 獲得超8個贊
您應該閱讀幾篇有關異常的文章,以了解返回值不是異常。不能采用“帶內” C方式或其他任何方式。
在不深入討論的情況下,應該在發現錯誤條件的地方拋出異常,并在可以有意義地處理錯誤條件的地方捕獲異常。返回值僅在層次結構堆棧中的第一個函數中處理,該函數可能會或不會如何處理問題。一個簡單的示例是一個配置文件,該文件可以將值檢索為字符串,并且還支持處理成類型的return語句:
class config {
// throws key_not_found
string get( string const & key );
template <typename T> T get_as( string const & key ) {
return boost::lexical_cast<T>( get(key) );
}
};
現在的問題是,如果找不到密鑰,您將如何處理。如果您使用返回碼(例如,在返回過程中),則問題在于get_as必須處理錯誤碼get并采取相應措施。由于它并不真正知道該怎么辦,因此唯一明智的做法是手動向上游傳播錯誤:
class config2 {
pair<string,bool> get( string const & key );
template <typename T> pair<T,bool> get_as( string const & key ) {
pair<string,bool> res = get(key);
if ( !res.second ) {
try {
T tmp = boost::lexical_cast<T>(res.first);
} catch ( boost::bad_lexical_cast const & ) {
return make_pair( T(), false ); // not convertible
}
return make_pair( boost::lexical_cast<T>(res.first), true );
} else {
return make_pair( T(), false ); // error condition
}
}
}
該類的實現者必須添加額外的代碼來轉發錯誤,并且該代碼與問題的實際邏輯混雜在一起。在C ++中,這可能比為多種賦值設計的語言(a,b=4,5)更為繁重,但是,如果邏輯取決于可能的錯誤(此處lexical_cast僅在有實際字符串的情況下執行調用),則必須緩存值變成變量。

TA貢獻1871條經驗 獲得超13個贊
它不是Go語言,但在Lua中,多次返回是處理異常的極為常見的習慣用法。
如果您有類似的功能
function divide(top,bottom)
if bottom == 0 then
error("cannot divide by zero")
else
return top/bottom
end
end
然后,當bottom值為0時,將引發異常,并且程序的執行將停止,除非您將函數包裝divide在pcall(或受保護的調用)中。
pcall 總是返回兩個值:第一個是result是一個布爾值,指示該函數是否成功返回,第二個結果是返回值或錯誤消息。
以下(偽造的)Lua代碼片段顯示了此用法:
local top, bottom = get_numbers_from_user()
local status, retval = pcall(divide, top, bottom)
if not status then
show_message(retval)
else
show_message(top .. " divided by " .. bottom .. " is " .. retval)
end
當然pcall,如果您要調用的函數已經以的形式返回,則不必使用status, value_or_error。
多次回報對于Lua來說已經足夠好了,所以雖然不能確保它對Go足夠好,但是它支持了這個想法。
- 3 回答
- 0 關注
- 261 瀏覽
添加回答
舉報