使用隐式方法
最常见和通用的方法是使用在Predef中定义的implicitly方法:
def add[T: Numeric](x: T, y: T) = implicitly[Numeric[T]].plus(x,y)
很明显,这样有些啰嗦,并且需要重复类型类的名称。
引用evidence参数(不要这么做!)
另一种选择是使用编译器自动生成的隐式evidence参数的名称:
def add[T: Numeric](x: T, y: T) = evidence$1.plus(x,y)
这种技术甚至合法令人惊讶,实践中不应依赖证据参数名称可能会发生变化。
更高级别的上下文(介绍context
方法)
相反,可以使用加强版的implicitly
方法。请注意,隐式方法定义为:
def implicitly[T](implicit e: T): T = e
这种方法仅依赖于编译器将正确类型的隐式对象从周围的范围插入方法调用,然后返回它。我们可以更好地做到:
def context[C[_], T](implicit e: C[T]) = e
这使我们能够将
add
方法定义为:
def add[T: Numeric](x: T, y: T) = context.plus(x,y)
context
方法的类型参数Numeric
和T
是从作用域中推断出来的!不幸的是,在某些情况下,这个context
方法将无法工作。例如,当一个类型参数有多个上下文边界或者有多个参数具有不同的上下文边界时,我们可以通过稍微复杂一点的版本来解决后一个问题:
class Context[T] { def apply[C[_]]()(implicit e: C[T]) = e }
def context[T] = new Context[T]
这个版本要求我们每次都指定类型参数,但可以处理多个类型参数。
def add[T: Numeric](x: T, y: T) = context[T]().plus(x,y)
context
方法的聪明技巧! - Daniel Spiewakdef add[T: Numeric](x: T, y: T) = _.plus(x,y)
。 - shellholic