约束接受 Both(二)的函数的返回类型



我正在尝试制作这样的函数:

 def foo(x: Either[String, Int]) = x match {
   case Left(s) => Left("foo:" + s)
   case Right(n) => Right(n+1)
 }

这有效,但我正在寻找一种方法来向调用者保证,结果将始终与输入的类型相同 - 如果输入是左,你会得到左,如果它是右,你会得到右。

有人能想到我可以用来做到这一点的巧妙技巧吗?

我知道,我可以这样做:

 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]

。但最终的演员阵容是丑陋的:(这个声明将是一个基本特征的抽象成员,几个实现"插件"将需要覆盖,我不想让所有插件都必须做这种类型转换的事情。

我还可以fooStringfooInt两个单独的函数...但这是我想避免的事情,因为一些考虑因素,特定于我正在处理的特定 API。

还有其他想法吗?

如果您不限于使用任一,则可以使用类型类 -

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)

这个签名实际上并没有说出你想说的话:

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
}

(它仍然有fooStringfooInt,但不在公共API中。

最新更新