takafumi blog

日々の勉強メモ

Scalaでもtry-catchを使う方がよい事もある

環境   Scala 2.13.6

Scalaだと例外を常にTryで処理しがちなので、反省メモ。

もちろん単純に例外出す可能性ある個所をTryで包むのは問題ない。
困るのはTry[Either[L, R]] みたいなネストを避けたい時。

refinedとかでよくある。
例えば以下は単純にStringEither[String, PosInt]に変換している。

import cats.implicits._
import eu.timepit.refined.api.RefType
import eu.timepit.refined.types.numeric.PosInt
import scala.util.Try

def s2pi(s: String): Either[String, PosInt] =
  Try(s.toInt).toEither
    .leftMap(_.getMessage)
    .flatMap(RefType.applyRef[PosInt](_))

val etPiR = s2pi("1") // Right(1)
val etPiL = s2pi("a") // Left(For input string: "a")

読みずらい!
まあ正直言うと、このくらいならまだマシで、実際コード書いているともっと複雑になる事も多々ある。

こういうTryとEitherのネストを避けようとするなら、以下のように書くのが断然読みやすい。

import eu.timepit.refined.api.RefType
import eu.timepit.refined.types.numeric.PosInt
import scala.util.Try

def s2piVer2(s: String): Either[String, PosInt] =
  try RefType.applyRef[PosInt](s.toInt)
  catch { case t: Throwable => Left(t.getMessage) }

val etPiV2R = s2piVer2("1") // Right(1)
val etPiV2L = s2piVer2("a") // Left(For input string: "a")