Scala:通用方法隐式参数

时间:2016-02-12 07:41:58

标签: scala generics implicit

我遇到了一段代码片段而无法理解它。摘录如下:

  implicit val dummyVisit = Visit("", 1L, 1, 1, 1, 1L)
  implicit val dummyOrder = Order("", 1L, 1, 1, 1, 1L)

  def process[T](events : Array[T])(implicit t: T):Unit = {
    println(t)
    if(!events.isEmpty)
      t match {
        case r: Order => processOrder(events.asInstanceOf[Array[Order]])
        case r: Visit => processVisit(events.asInstanceOf[Array[Visit]]);
      }
  }

  def processOrder(arr: Array[Order]): Unit = { println(arr.size) }
  def processVisit(arr: Array[Visit]): Unit = { println(arr.size) }

implicit变量t,需要dummyVisit& dummyOrder存在。

问题

  1. 这是使用implicit parameter的正确方法吗?

  2. 有没有更好的方法来获取T的类类型,而不使用隐式参数?

1 个答案:

答案 0 :(得分:2)

捕获参数的类型是隐式参数的预期用途之一。

虽然我写这样的东西有点不同:

import scala.reflect.ClassTag

// `sealed` ensures that no extra evidences can be defined elsewhere
sealed abstract class Evidence[T](implicit val tag: ClassTag[T])
object Evidence {
  implicit object visitEvidence extends Evidence[Visit]
  implicit object orderEvidence extends Evidence[Order]
}

def process[T](events: Array[T])(implicit ev: Evidence[T]) = {
  import ev.tag // import ClassTag[T] to allow matching on array element types
  events match {
    case Array() => // don't process empty arrays
    case arr: Array[Order] => processOrder(arr)
    case arr: Array[Visit] => processVisit(arr)
  }
}

此代码避免创建无意义的虚拟实例,并使用asInstanceOf进行类型转换。

进一步的步骤是在隐式参数中捕获处理操作本身,并完全避免每个案例的显式match。这也称为类型类模式:

sealed trait ProcessArray[T] {
  def apply(arr: Array[T]): Unit
}
object ProcessArray {
  implicit object processVisitArray extends ProcessArray[Visit] {
    def apply(arr: Array[Visit]) = { println(arr.size) }
  }
  implicit object processOrderArray extends ProcessArray[Order] {
    def apply(arr: Array[Order]) = { println(arr.size) }
  }
}
def process[T](array: Array[T])(implicit proc: ProcessArray[T]) = {
  if (array.nonEmpty) proc(array)
}