亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Google的“ Go”語言多值返回語句是異常的替代方法嗎?

Google的“ Go”語言多值返回語句是異常的替代方法嗎?

Go
蠱毒傳說 2021-04-14 18:15:43
在我看來,Google對例外的替代方法是GO:多值返回“ return val,err;”GO,C ++:無檢查(早期返回)GO,C ++:“處理該死的錯誤”(我的說法)C ++:斷言(表達式)GO:延遲/緊急/恢復是詢問此問題后添加的語言功能多值回報是否足夠有用以充當替代選擇?為什么將“資產”視為替代品?如果發生程序錯誤而無法正確處理的程序而導致程序停止運行,那么Google認為可以嗎?有效的GO:多個返回值Go的不尋常功能之一是函數和方法可以返回多個值。這可以用來改善C程序中的一些笨拙的習慣用法:帶內錯誤返回(例如,對于EOF為-1)和修改自變量。在C語言中,寫入錯誤由負數表示,錯誤代碼被隱藏在易失性位置中。在Go中,Write可以返回一個計數和一個錯誤:“是的,您寫了一些字節,但不是全部,因為您填滿了設備”。軟件包os中* File.Write的簽名為:func (file *File) Write(b []byte) (n int, err Error)如文檔所述,當n!= len(b)時,它返回寫入的字節數和非nil錯誤。這是一種常見的樣式。有關更多示例,請參見錯誤處理部分。有效的GO:命名結果參數可以給Go函數的返回或結果“參數”指定名稱,并將其用作常規變量,就像傳入的參數一樣。命名后,函數開始時會將它們初始化為其類型的零值;否則,將它們初始化為零。如果函數執行不帶參數的return語句,則將結果參數的當前值用作返回值。名稱不是強制性的,但它們可以使代碼更短,更清晰:它們是文檔。如果我們命名nextInt的結果,則顯而易見,返回的int是哪個。func nextInt(b []byte, pos int) (value, nextPos int) {由于命名結果已初始化并綁定到未經修飾的返回值,因此它們既可以簡化又可以澄清。這是io.ReadFull的一個很好使用它們的版本:func ReadFull(r Reader, buf []byte) (n int, err os.Error) {  for len(buf) > 0 && err == nil {    var nr int;    nr, err = r.Read(buf);    n += nr;    buf = buf[nr:len(buf)];  }  return;}Panic是一個內置函數,可停止常規控制流并開始發出恐慌。當函數F調用緊急情況時,F的執行停止,F中任何延遲的函數都將正常執行,然后F返回其調用方。對于呼叫者,F然后表現得像是發生了恐慌。該過程將繼續執行堆棧,直到返回當前goroutine中的所有函數為止,此時程序崩潰。緊急事件可以通過直接調用緊急事件來啟動。它們也可能是由運行時錯誤引起的,例如越界數組訪問?;謴褪且粋€內置功能,可以重新獲得對緊急恐慌例程的控制?;謴蛢H在延遲函數內部有用。在正常執行期間,恢復調用將返回nil并且沒有其他效果。如果當前goroutine處于恐慌狀態,則調用recovery會捕獲為panic提供的值并恢復正常執行。這是一個示例程序,演示了恐慌和延遲的機制:<snip>有關恐慌和恢復的真實示例,請參閱Go標準庫中的json包。它使用一組遞歸函數對JSON編碼的數據進行解碼。遇到格式錯誤的JSON時,解析器調用panic會將堆棧退回到頂層函數調用,該函數從panic中恢復并返回適當的錯誤值(請參見decode.go中的“ error”和“ unmarshal”函數) 。regexp包的Compile例程中有此技術的類似示例。Go庫中的約定是,即使程序包內部使用了緊急情況,其外部API仍會顯示顯式的錯誤返回值。defer的其他用法(在先前給出的file.Close()示例之外)包括釋放互斥鎖:mu.Lock()   defer mu.Unlock
查看完整描述

3 回答

?
SMILET

TA貢獻1796條經驗 獲得超4個贊

多次返回不是Go唯一的,并且不能替代異常。用C(或C ++)術語來說,它們是返回包含多個值的結構(對象)的簡潔且用戶友好的替代方法。

如果您僅此意思,它們確實提供了指示錯誤的便捷方法。

為什么將“資產”視為替代品?

斷言最初用于調試。他們在程序處于“不可能”狀態的情況下暫停了該程序,設計認為這種情況不應該發生,但是無論如何還是會發生。返回錯誤不太可能有太大幫助。代碼庫顯然還無法正常工作,那么到底如何才能成功恢復呢?當有一個需要引起注意的錯誤時,您為什么還要這么做?

在生產代碼中使用斷言有些不同-顯然存在性能和代碼大小方面的顧慮,因此通常的方法是在代碼分析和測試確信您“不可能”的情況確實不可能時,將它們刪除。但是,如果您正在以這種偏執級別運行代碼,它正在對自身進行審核,那么您還可能會偏執于:如果讓代碼繼續在“不可能”狀態下運行,那么它可能會做一些危險的事情:破壞有價值的數據,從而超出了堆棧分配的范圍,并可能創建安全漏洞。同樣,您只想盡快關閉。

您斷言的內容確實與您使用異常的內容不同:當C ++和Java之類的編程語言為“不可能”的情況(logic_error,ArrayOutOfBoundsException)提供異常時,它們無意間鼓勵一些程序員認為他們的程序應該嘗試從真正無法控制的情況中恢復過來。有時這是適當的,但是出于充分的原因,這里有Java建議不要捕獲RuntimeExceptions。偶爾捕獲一個是一個好主意,這就是它們存在的原因。捕獲它們幾乎總是一個好主意,這意味著它們無論如何都等于暫停了程序(或至少是線程)。


查看完整回答
反對 回復 2021-04-26
?
嗶嗶one

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僅在有實際字符串的情況下執行調用),則必須緩存值變成變量。




查看完整回答
反對 回復 2021-04-26
?
慕桂英4014372

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足夠好,但是它支持了這個想法。


查看完整回答
反對 回復 2021-04-26
  • 3 回答
  • 0 關注
  • 261 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號