私はScalaのケースクラスを抽象化する方法を模索しています。例えば、ここでは(スカラ座2.10.0-M1と-Yvirtpatmat
を使用して)Either[Int, String]
ための試みである。この定義を考えるとケースクラスの抽象化
trait ApplyAndUnApply[T, R] extends Function1[T, R] {
def unapply(r: R): Option[T]
}
trait Module {
type EitherIntOrString
type Left <: EitherIntOrString
type Right <: EitherIntOrString
val Left: ApplyAndUnApply[Int, Left]
val Right: ApplyAndUnApply[String, Right]
}
が、私はそのような何かを書くことができます:ここで
def foo[M <: Module](m: M)(intOrString: m.EitherIntOrString): Unit = {
intOrString match {
case m.Left(i) => println("it's an int: "+i)
case m.Right(s) => println("it's a string: "+s)
}
}
は最初のものです
object M1 extends Module {
type EitherIntOrString = String
type Left = String
type Right = String
object Left extends ApplyAndUnApply[Int, Left] {
def apply(i: Int) = i.toString
def unapply(l: Left) = try { Some(l.toInt) } catch { case e: NumberFormatException => None }
}
object Right extends ApplyAndUnApply[String, Right] {
def apply(s: String) = s
def unapply(r: Right) = try { r.toInt; None } catch { case e: NumberFormatException => Some(r) }
}
}
:Either
の表現がString
あるモジュールの実装のsが、次の作品そう期待して、Left
とRight
本当に排他ます
scala> foo(M1)("42")
it's an int: 42
scala> foo(M1)("quarante-deux")
it's a string: quarante-deux
これまでのところは良いです。予想通り
object M2 extends Module {
type EitherIntOrString = Either[Int, String]
type Left = scala.Left[Int, String]
type Right = scala.Right[Int, String]
object Left extends ApplyAndUnApply[Int, Left] {
def apply(i: Int) = scala.Left(i)
def unapply(l: Left) = scala.Left.unapply(l)
}
object Right extends ApplyAndUnApply[String, Right] {
def apply(s: String) = scala.Right(s)
def unapply(r: Right) = scala.Right.unapply(r)
}
}
は、しかし、これは動作しません:
scala> foo(M2)(Left(42))
it's an int: 42
scala> foo(M2)(Right("quarante-deux"))
java.lang.ClassCastException: scala.Right cannot be cast to scala.Left
正しい結果を取得する方法があります私の第二の試みはModule.EitherIntOrString
のための自然な実装としてscala.Either[Int, String]
を使用するのですか?
グレート説明!私は私の問題を解決することに決めました...パターンマッチングを使用しないことによって:-)折り畳み機能を定義する方が簡単で堅牢です。 – betehess