我需要建立具有多個欄位的記錄。
記錄定義如下:
class Record(
f1: Int,
f2: String,
...
err: String
)
邏輯是這樣的:
record.f1 = get_f1()
record.f2 = get_f2()
...
對 get_f1 等的呼叫可能會引發例外。發生這種情況時,我們將 record.err 設定為例外訊息。
現在,我的 hacky 解決方案是使用可變 Record 實體并逐步修補欄位。當例外發生時,我會從外部函式中捕獲它并設定 err 欄位。
問題是如何以更實用的方式實作這一點?
- - - 編輯 - - -
我們需要 err 欄位來輸出第一個例外 當例外發生時,我們仍然要輸出已經填充的欄位
uj5u.com熱心網友回復:
問題是如何以更實用的方式實作這一點?
通過以功能樣式正確建模。
首先,讓我們err從 中洗掉欄位case class,而是使用 useEither
第二,讓我們正確處理nullsusingOption
最后,讓我們使用像cat這樣的函式庫。
最終結果將是這樣的:
import cats.data.EitherNec
import cats.syntax.all._
type Error = String // You may use a better data type.
final case class Record(
f1: Int,
f2: String,
f3: Boolean
)
object Record {
def fromRawData(f1: Option[Int], f2: Option[String], f3: Option[Boolean]): EitherNec[Error, Record] =
(
f1.toRightNec(left = "F1 was empty"),
f2.toRightNec(left = "F2 was empty"),
f3.toRightNec(left = "F3 was empty")
).parMapN(Record.apply)
}
The
EitherNec[E, A]只是Either[NonEmptyChain[E], A]
含義的別名,如果它是 aLeft它將包含所有錯誤;這也意味著必須至少有一個錯誤。
隨時提出您可能有的任何后續問題。
如果您不想使用貓,可以將 ; 替換parMapN為for; 但這將在第一次失敗時停止。
您可以看到這里運行的代碼。
uj5u.com熱心網友回復:
這是一種(主要)功能性的方法:
import scala.util.{Try, Success, Failure}
Try {
Record(getf1(), getf2(), "")
} match {
case Success(r) => r
case Failure(e) => Record(0, "", e.getMessage)
}
如果Try運行中的代碼正常,那么它將回傳Success并且match將提取值并回傳它。
如果代碼拋出例外,那么它將被捕獲Try并回傳Failure。將match捕獲錯誤代碼,然后創建一個值,Return并將其err設定為來自例外的錯誤訊息。
正如其他人所提到的,該Either型別是處理錯誤情況的更好方法,因為它從Record類本身中洗掉了錯誤資訊:
Try {
Record(getf1(), getf2())
}.toEither
結果將是Right(<record>)成功或Left(<exception>)錯誤。您可以使用match來確定給出了哪個答案。
對于修改后的問題,您需要使用嵌套的Try呼叫鏈,記錄中的每個欄位都有一層嵌套。
Try(getf1()) match {
case Failure(e) => Record(0, "", e.getMessage)
case Success(f1) =>
Try(getf2()) match {
case Failure(e) => Record(f1, "", e.getMessage)
case Success(f2) => Record(f1, f2, "")
}
}
這個相當曲折的代碼是問題中混合錯誤處理方法的結果。更標準的設計將對整個記錄(如上面的示例)或每個單獨的欄位(通過將每個欄位設為Option或Either值)進行錯誤處理。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/486235.html
標籤:斯卡拉
