[英]Are there problems using Try or Either for error handling in public/open source Scala APIs?
我注意到許多開源Scala API使用Future
(如Slick)或Java風格的異常處理(如spray-json)而不是Try
或Either
。
在沒有長時間運行或異步的簡單開源API中返回Try
或Either
是否存在問題? 我應該避免這些,如果是這樣,我應該使用什么呢?
(顯然,我更傾向於使用核心Scala API而不是第三方庫,例如Scalaz,以避免迫使下游用戶使用這些庫。)
Try
包裝非異步操作的異常是很好的。
但是,我認為使用異常實例返回非異常錯誤條件是不正確的 。 當API是異步的並且使用Future
時,我也是這樣。 將異常錯誤與業務錯誤混合容易導致API客戶端(也就是我:)的錯誤處理不正確/不充分。
如果您仍然決定使用例外來表示您的業務錯誤,請記住異常帶有隱藏價格:構建堆棧跟蹤。 如果您創建自己的業務異常並混合使用scala.util.control.NoStackTrace
則可以減輕這種scala.util.control.NoStackTrace
。
Scala標准庫中的默認Either
實現是無偏的,這意味着區分成功和失敗的情況僅依賴於約定:
右是正確的(正確),因此左錯(錯誤)。
不偏不倚的一面也讓追隨“快樂”的道路變得痛苦(或使錯誤恢復脫穎而出)
此時您的最佳選擇(scala 2.11.6和相應的標准庫)將根據您的依賴關系和要向用戶公開的API而有所不同,但它不會來自scala標准庫。
Validation
或\\/
是一個選項 Or
類型是一個很好的輕量級解決方案,如果你不想拉入整個scalaz。 它是成熟的,是從金字塔中提取出來的 modes
允許您讓API的客戶端決定他想要取回的類型(例如,這種方法在parboiled2中使用)。 我不知道圖書館作者或編譯時間的成本是多少。 您可能已經依賴於提供自己的validation
類型的庫。 例如,play-json有一個JsResult類型,其驗證類似於能力。 根據您正在處理的內容重用類型可能是有意義的。
在以下情況下返回Try [T]:正確的結果和不正確的結果(即錯誤)之間存在語義差異。 這是因為:
嘗試是偏右的(它適用於地圖,平面地圖和for-comprehensions)。
失敗案例是一個Throwable,這很重要,因為throwable總是清楚地意味着甚至超出了代碼邊界的錯誤。
警告 :堆棧跟蹤生成有時是一種開銷,但並非總是如此! 在過早優化代碼之前要三思而后行:堆棧跟蹤帶有許多有用的調試信息。 如果您以后發現您確實需要跳過堆棧跟蹤生成,沒問題:使用
with NoStackTrace
如上所示。
def validate(s:String):Try[String] = Option(s).filter(!_.isEmpty).map(Try(_)).getOrElse(new Exception("bad input") with NoStackTrace
使用[L,R]時 :兩種情況都可以接受,但它們是互斥的(即[Integer,Float])。 出於這個原因,盡管Scalaz的家伙們不得不對此發表評論,但我相信這兩者都是公正的。
def parseNum(s:String):Either[Int,String] = Try(parseInt(s)).map(Left(_)).getOrElse(Right(s))
類似於Either 時使用Tuple ,但是當你有N時,非互斥值(你知道所有都有用)
def parseAndReturn(s:String):(Integer,String) = (parseInt(s), s)
當 T可以為空時,或者當你處於與Try [T]相同的情況時, 返回一個選項[T] ,但是你沒有給出關於為什么出錯的原因。
def attemptToparse(s:String):Option[Result] = Try(parse(s)).toOption
我同意Try
是捕獲/通知異常,而不是返回業務/驗證錯誤。 Scalaz是一個非常好的選擇,但是如果你不想依賴它,我認為Either
是好的,不偏不倚是令人討厭但不是交易破壞者恕我直言:一旦你建立了Right是有效結果的約定,你可以“正確偏見”它與.rightProjection
(如果你只想處理錯誤,你可以做左投影。另一種選擇是使用Either的折疊fold[X](fa: (A) ⇒ X, fb: (B) ⇒ X): X
myEither.fold(dealWithErrors _, happyPath _ )
fold[X](fa: (A) ⇒ X, fb: (B) ⇒ X): X
喜歡myEither.fold(dealWithErrors _, happyPath _ )
(雖然這意味着dealWithErrors
和happyPath
返回相同的類型)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.