Scala 专题教程-隐式变换和隐式参数(7):View 限定

jerry Scala 2015年11月25日 收藏

上篇的例子

def maxListImpParam[T](element:List[T])
                    (implicit orderer:T => Ordered[T]):T =
    element match {
      case List() =>
        throw new IllegalArgumentException("empty list!")
      case List(x) => x
      case x::rest =>
        val maxRest=maxListImpParam(rest)(orderer)
        if(orderer(x) > maxRest) x
        else maxRest
    }

其中函数体部分有机会使用implicit却没有使用。要注意的是当年在参数中使用implicit类型时,编译器不仅仅在需要时补充隐含参数,而且编译器也会把这个隐含参数作为一个当前作用域内可以使用的隐含变量使用,因此在使用隐含参数的函数体内可以省略掉implicit的调用而由编译器自动补上.
因此代码可以简化为:

def maxList[T](element:List[T])
                    (implicit orderer:T => Ordered[T]):T =
    element match {
      case List() =>
        throw new IllegalArgumentException("empty list!")
      case List(x) => x
      case x::rest =>
        val maxRest=maxList(rest)
        if(x > maxRest) x
        else maxRest
    }

编译在看到 x > maxRest 发现类型不匹配,编译器不会马上停止编译,相反,它会检查是否有合适的隐含转换来修补代码,在中,它发现orderer可用。因此编译器自动改写为orderer(x)> maxRest。同理我们在递归调用maxList省掉了第二个隐含参数,编译器也会自动补上。
同时我们发现,maxList代码定义了隐含参数orderer,而在函数体中没有地方直接引用到该参数,因此你可以任意改名orderer,比如下面几个函数定义是等价的:

def maxList[T](element:List[T])
                    (implicit orderer:T => Ordered[T]):T =
    ...
	
def maxList[T](element:List[T])
                    (implicit iceCream:T => Ordered[T]):T =
    ...

由于在Scala这种用法非常普遍,Scala中专门定义了一种简化的写法?View限定。如下:

def maxList[T <% Ordered[T]](element:List[T]) :T =
    element match {
      case List() =>
        throw new IllegalArgumentException("empty list!")
      case List(x) => x
      case x::rest =>
        val maxRest=maxList(rest)
        if(x > maxRest) x
        else maxRest
    }

其中 implicit def identity[A](x:A): A =x

在这种情况下,该变换不做任何处理,直接返回传入的对象。