scala/scala3
Either using cats and ox
wefree
2024. 4. 4. 19:06
cats 와 ox 를 활용해 Either 를 강력하게 사용하기
Cats Either Helper
- .asRight .asLeft
- .leftMap .map
- Either.catchNonFatal, Either.catchOnly
- Either.fromTry, Either.fromOption
Ox Either Helper
코드
libraryDependencies += "org.typelevel" %% "cats-core" % "2.10.0",
libraryDependencies += "com.softwaremill.ox" %% "core" % "0.1.0"
import cats.*
import cats.syntax.all.*
import scala.util.{Failure, Try}
enum AppError(val code: Int, val message: String, val detail: String) extends Throwable {
case BadRequest(override val detail: String) extends AppError(400, "bad request", detail)
case ServerError extends AppError(500, "server error", "")
}
@main def Main(): Unit = {
val e2: Either[Throwable, Int] = Either.catchNonFatal(2)
val e3: Either[ArithmeticException, Int] = Either.catchOnly[ArithmeticException](1 / 0)
val e4: Either[AppError, Int] = Either
.fromTry[Int](Failure(Exception("something wrong")))
.leftMap(e => AppError.BadRequest(e.getMessage))
// val t4: Try[Int] = e4.toTry
import ox.either
import ox.either.{ok, fail}
val result: Either[Unit | Throwable, Int] = either { // o5 때문에 Left 로 Unit 이 추가됨
val e1: Either[AppError, Int] = 4.asRight[AppError]
val v1: Int = e1.ok()
val o5: Option[Int] = none[Int]
val v2345: Int = v1 match {
case 2 => e2.ok()
case 3 => e3.ok()
case 4 => e4.ok()
case 5 => o5.ok() // Option 을 Either 로 변환하지 않더라도 자연스럽게 composing 될 수 있다 !!!
case _ => AppError.ServerError.fail() // 한번에 탈출(?) 해 최종 결과 either Left 로 직행할 수 있다.
}
v1 + v2345
}
result match {
case Right(v) => println(s"success: $v") // when v1 == 2
case Left(e: AppError) => println(s"error: code=${e.code}, message=${e.message}, detail=${e.detail}") // when v1 == 4
case Left(e: Throwable) => println(s"error: unknown, ${e.getMessage}") // when v1 == 3
case Left(()) => println(s"error: option empty") // when v1 == 5
}
println(result)
}
scala.util.control.Exception.catching
https://www.scala-lang.org/api/current/scala/util/control/Exception$.html
import scala.util.control.Exception._
import java.net._
val s = "https://www.scala-lang.org/"
val x2: Either[Throwable,URL] =
catching(classOf[MalformedURLException], classOf[NullPointerException]).either(new URL(s))