我正在尝试制作这样的函数:
def foo(x: Either[String, Int]) = x match {
case Left(s) => Left("foo:" + s)
case Right(n) => Right(n+1)
}
这样可行,但我正在寻找一种方法来确保调用者,结果将始终与输入的类型相同 - 如果输入为Left,则返回Left,如果是Right,则右转。
有人可以想到一个可以用来做那个的巧妙技巧吗?
我知道,我可以这样做:
def foo[T <: Either[String, Int]](x: T): T = (x match {
case Left(s) => Left("foo:" + s)
case Right(n) => Right(n+1)
}).asInstanceOf[T]
...但是演员到底是丑陋的:( 这个声明将成为一个基本特征的抽象成员,即几个实现&#34;插件&#34;将需要覆盖,我不想让他们所有人都必须做这种类型铸造的事情。
我还可以创建两个单独的函数fooString
和fooInt
...但这是我想要避免的,因为某些考虑因素,特定于我特定的api继续努力。
还有其他想法吗?
答案 0 :(得分:2)
如果您不限于使用Either,则可以使用类型类 -
sealed trait Transformer[A] {
def transform(n: A): A
}
object Transformer {
implicit object IntTransformer extends Transformer[Int] { def transform(n: Int) = n + 1 }
implicit object StringTransformer extends Transformer[String] { def transform(s: String) = "foo:" + s }
}
def foo[A: Transformer](x: A)(implicit transformer: Transformer[A]) = transformer.transform(x)
答案 1 :(得分:1)
这个签名实际上并没有说出你想说的话:
val x = Left("a")
val y = foo[x.type](x)
y
的类型为x.type
,因此它必须是同一个实例,而不是。因此,如果您想避免强制转换,则需要更改签名。一种方法(未经测试):
trait LowPriorityFooImplicits { _: FooImplicits =>
implicit def eitherFoo(x: Either[String, Int]): Foo[Either[String, Int]] = new Foo(x) {
def foo() = x match {
case y: Left[String, Int] => y.foo()
case z: Right[String, Int] => z.foo()
}
}
trait FooImplicits extends LowPriorityFooImplicits {
sealed trait Foo[A <: Either[String, Int]](x: A) {
def foo(): A
}
implicit def leftFoo(x: Left[String, Int]): Foo[Left[String, Int]] = new Foo(x) {
def foo() = Left(fooString(x.value))
}
implicit def rightFoo ...
// x will be implicitly converted from a subtype of Either[String, Int]
def foo[A](x: Foo[A]): T = x.foo()
protected def fooString(s: String) = "foo:" + s
protected def fooInt(n: Int) = n + 1
}
(它仍然有fooString
和fooInt
,但不在公共API中。)