Scala - 对任何

时间:2015-07-11 03:44:57

标签: scala type-conversion

我希望定义一个函数,它接受两个类型为Any的args并尝试添加它们,如下所示:

def plus(x:Any,y:Any):Try[Any] = {
   ...
}

如果操作数是可以添加的类型(算术,不是字符串连接或类似的东西),则产生成功,如果不是,则返回Failure。例如:

val x:Any = 1
val y:Any = 2
val z = plus(x,y) // z = Success(3)

val x:Any = "wrong"
val y:Any = 2
val z = plus(x,y) // z = Failure(...)

并且,我希望通过添加来进行类型提升工作:Int + Int => Int,Int + Double =>双,等等。

我知道必须有一个聪明而简洁的方法来做到这一点,而不必检查匹配的每种可能的类型组合。我对Scala很新(只有一周),所以我会很感激任何建议。

2 个答案:

答案 0 :(得分:1)

在您的示例中,您知道编译时的参数类型。在这种情况下,您可以使用类型系统做得更好:

scala> def plus[T: Numeric](a: T, b: T) = implicitly[Numeric[T]].plus(a, b)
plus: [T](a: T, b: T)(implicit evidence$1: Numeric[T])T

scala> plus(1, 2)
res0: Int = 3

scala> plus(1, 2.5)
res1: Double = 3.5

scala> plus(1, "2")
<console>:9: error: could not find implicit value for evidence parameter of type Numeric[Any]
              plus(1, "2")
                  ^

答案 1 :(得分:0)

已更新:哎呀!我错过了你问题的最后一部分。如果您尝试添加两种不同的类型,例如Int + Double => Double,我所解释的并不起作用。

我认为你可以使用Scalaz的Monoid

简单地说,它看起来像这样

trait Monoid[F] extends Semigroup[F] {
  def zero: F
  def append(f1: F, f2: => F): F
}

因此,如果您想使用它,您需要做的就是导入Scalaz

import scalaz._
import Scalaz._

然后你可以简单地做

1 |+| 1        // result: 2

"a" |+| "b"    // result: ab

BigInt(100) |+| BigInt(100)    // BigInt(200)

Scalaz为大多数已知类型(如Int,BigInt,BigDecimal,String等)提供隐式类型转换,但如果您有自己的类型并且想要使其可附加,则可以轻松完成。

我们假设您有类似

的类型
case class Something(value: Int)

您可以使用隐式类型转换,例如。

  implicit def SomethingMonoid = new Monoid[Something] {
    override def zero: Something = Something(0)
    override def append(f1: Something, f2: => Something): Something = Something(f1.value |+| f2.value)  // you can even use |+| here as value is Int
  }

现在,你可以做到

Something(10) |+| Something(100)    // result: Something(110)

如果要重复使用它,只需使用Scalaz导入SomethingMonoid

import scalaz._
import Scalaz._
import your.package.SomethingMonoid

// Or
import scalaz._
import Scalaz._

// ...
val somethingMonoid = your.package.SomethingMonoid

然后你可以做

Something(111) |+| Something(222)    // result: Something(333)

使用Monoid来处理结果比使用方法更好并返回Try [T]因为你没有得到编译时类型安全性而Monoid会给你一个编译时错误,如果你做的话,< / p>

Something(10) |+| 100    // a compile-time error

如果你真的想拥有自己的加号,你可以做这样的事情

def plus[T](x: T, y: T)(implicit monoid: Monoid[T]): Try[T] = Try(monoid.append(x, y))
正如我上面解释的那样使用Scalaz,但是当类型不匹配时你会得到一个编译时错误,所以没有必要使用Try除非计算可能会引发一些异常。

plus(1, 2)        // result: 3
plus(Something(1), Something(9))    // result: Something(10)
plus("one", 2)    // result: a compile-time error