Scala:函数返回未知类型

时间:2015-05-11 18:49:22

标签: scala types numbers

如果我想创建一个添加两种不同类型值的add方法,如:

add[T,S](op1: T, op2: S): ? = ...

我能想到的最值得注意的例子是基本数字类型。如果我添加一个Byte和一个Int,那么它将返回一个Int。如果添加了两个字节,它可以返回一个Int,具体取决于字节的-127到128限制是否被破坏。

如果我想创建具有相同特征的类,我希望它能做同样的事情。

一种可能的解决方案是让类扩展相同的特征或类。但是对于Scala原始类型的示例,这不适用,因为Int,Double,Float,Byte除了Any之外不共享共同的祖先。

我还查看了Numeric [T]特征,但在添加不同的原始类型时似乎没有帮助。

由于 启

1 个答案:

答案 0 :(得分:5)

这是某种联合类型类的一个主要例子。

首先定义一个与Numeric[T]类似的东西,但是为了可添加性:

trait Addable[T, S] {
  type Result
  def add(x: T, y: S): Result
}

现在,定义您的add功能:

def add[T,S](op1: T, op2: S)(implicit op: Addable[T, S]): op.Result =
  op.add(op1, op2)

您需要做的就是为Addable创建隐式实例:

// Put them in the companion object, so the implicits are available
// without explicit import
object Addable {
  // Make any numeric addable
  implicit def numericAddable[T : Numeric]: Addable[T, T] = {
    new Addable[T, T] {
      type Result = T
      def add(x: T, y: T): T = {
        val op = implicitly[Numeric[T]]
        op.plus(x, y)
      }
    }
  }
}

但您现在还可以定义自己的类并定义(不对称)添加功能:

case class A(x: Int)
case class B(x: Int)
case class C(x: Int)

implicit object AddABC extends Addable[A,B] {
  type Result = C
  def add(x: A, y: B): C = C(x.x + y.x)
}

这将允许你写:

add(A(1), B(2))

但是,其中任何一个都会在编译时失败:

add(A(1), A(2))
add(B(1), A(2))
add(B(1), B(2))

不幸的是,这对弱的符合数字类型不起作用:

add(1, 1) // compiles
add(1.0, 1.0) // compiles
add(1, 1.0) // fails to compile

another post判断,除了手动定义案例(当然还有一些辅助方法)之外,没有其他方法可以实现这一点。