如何通过Scala中的类方法传递类型参数?

时间:2019-06-30 15:41:53

标签: scala generics implicit

在我的项目中,我需要编写一个通用类,该类在单个方法中以特殊方式使用其处理程序来处理某些类型(在示例中使用数字表示)。

class A[T](val a:T){
    def doSomething(b:T):T = a match{
        case a : Int    => doSomethingWithIntOrDouble(b)
        case a : Double => doSomethingWithIntOrDouble(b)
        case _          => b
    }
    def doSomethingWithIntOrDouble(b:T)(implicit ev:Numeric[T]):T = 
        ev.plus(a,b)
}

<console>:13: error: could not find implicit value for parameter ev: Numeric[T]
                case a : Int    => doSomethingWithIntOrDouble(b)
                                                             ^
<console>:14: error: could not find implicit value for parameter ev: Numeric[T]
                case a : Double => doSomethingWithIntOrDouble(b)


我认为这是因为编译器选择了type参数,而不是实际的参数。告诉我,这有什么办法吗?

PS好吧,如果我们假设答案是正确的,那么有必要重载dosomething方法以实现多态。

class A[T](val a:T){
    def doSomething(b:T)(implicit ev:Numeric[T]):T = ev.plus(a,b)
    def doSomething(b:T):T = b
}

但是在这种情况下,会出现另一个问题。

scala> a.doSomething(2)
<console>:13: error: ambiguous reference to overloaded definition,
both method doSomething in class A of type (b: Int)Int
and  method doSomething in class A of type (b: Int)(implicit ev: Numeric[Int])Int
match argument types (Int)
       a.doSomething(2)

1 个答案:

答案 0 :(得分:1)

我不确定这是否是您想要的,但希望对您有所帮助。

基本上,您需要将T类型是数字的证据转发给外部方法。但是,您还必须处理不存在的情况。
在这种情况下,您可以像这样为隐式参数提供默认值:

class A[T](val a: T) {
  def doSomething(b: T)(implicit ev: Numeric[T] = null): T = Option(ev) match {
    case Some(ev) => doSomethingWithNumeric(b)(ev)
    case None     => b
  }

  def doSomethingWithNumeric(b: T)(implicit ev: Numeric[T]): T = 
    ev.plus(a, b)
}

似乎可行。

(new A(10)).doSomething(100) // res: Int = 110
(new A("hey")).doSomething("world") // res: String = "world"

请注意,如果您有很多方法,也许最干净的解决方案是使A成为特征,它具有两种实现,一种用于数字类型,另一种用于无数字类型。
将两个子类的构造函数都设为私有,并在伴随对象中为A创建一个 factory ,以请求隐式数值参数,如果找到,它将返回数值子类的新实例。