Scala 系列(十三)—— 隐式转换和隐式参数 (2)

1.我们上面定义formatted函数的时候使用了柯里化,如果你不使用柯里化表达式,按照通常习惯只有下面两种写法:

// 这种写法没有语法错误,但是无法通过编译 def formatted(implicit context: String, deli: Delimiters): Unit = { println(deli.left + context + deli.right) } // 不存在这种写法,IDEA直接会直接提示语法错误 def formatted( context: String, implicit deli: Delimiters): Unit = { println(deli.left + context + deli.right) }

上面第一种写法编译的时候会出现下面所示error信息,从中也可以看出implicit是作用于参数列表中每个参数的,这显然不是我们想要到达的效果,所以上面的写法采用了柯里化。

not enough arguments for method formatted: (implicit context: String, implicit deli: com.heibaiying.Delimiters)

2.第二个问题和隐式函数一样,隐式默认值不能存在二义性,否则无法通过编译,示例如下:

implicit val bracket = new Delimiters("(", ")") implicit val brace = new Delimiters("{", "}") formatted("this is context")

上面代码无法通过编译,出现错误提示ambiguous implicit values,即隐式值存在冲突。

2.2 引入隐式参数

引入隐式参数和引入隐式转换函数方法是一样的,有以下三种方式:

定义在隐式参数对应类的伴生对象中;

直接定义在执行代码的上下文作用域中;

统一定义在一个文件中,在使用时候导入。

我们上面示例程序相当于直接定义执行代码的上下文作用域中,下面给出其他两种方式的示例:

定义在隐式参数对应类的伴生对象中

class Delimiters(val left: String, val right: String) object Delimiters { implicit val bracket = new Delimiters("(", ")") } // 此时执行代码的上下文中不用定义 object ScalaApp extends App { def formatted(context: String)(implicit deli: Delimiters): Unit = { println(deli.left + context + deli.right) } formatted("this is context") }

统一定义在一个文件中,在使用时候导入

object Convert { implicit val bracket = new Delimiters("(", ")") } // 在使用的时候导入 import com.heibaiying.Convert.bracket object ScalaApp extends App { def formatted(context: String)(implicit deli: Delimiters): Unit = { println(deli.left + context + deli.right) } formatted("this is context") // 输出: (this is context) } 2.3 利用隐式参数进行隐式转换 def smaller[T] (a: T, b: T) = if (a < b) a else b

在Scala中如果定义了一个如上所示的比较对象大小的泛型方法,你会发现无法通过编译。对于对象之间进行大小比较,Scala和Java一样,都要求被比较的对象需要实现java.lang.Comparable接口。在Scala中,直接继承Java中Comparable接口的是特质Ordered,它在继承compareTo方法的基础上,额外定义了关系符方法,源码如下:

trait Ordered[A] extends Any with java.lang.Comparable[A] { def compare(that: A): Int def < (that: A): Boolean = (this compare that) < 0 def > (that: A): Boolean = (this compare that) > 0 def <= (that: A): Boolean = (this compare that) <= 0 def >= (that: A): Boolean = (this compare that) >= 0 def compareTo(that: A): Int = compare(that) }

所以要想在泛型中解决这个问题,有两种方法:

1. 使用视图界定 object Pair extends App { // 视图界定 def smaller[T<% Ordered[T]](a: T, b: T) = if (a < b) a else b println(smaller(1,2)) //输出 1 }

视图限定限制了T可以通过隐式转换Ordered[T],即对象一定可以进行大小比较。在上面的代码中smaller(1,2)中参数1和2实际上是通过定义在Predef中的隐式转换方法intWrapper转换为RichInt。

// Predef.scala @inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)

为什么要这么麻烦执行隐式转换,原因是Scala中的Int类型并不能直接进行比较,因为其没有实现Ordered特质,真正实现Ordered特质的是RichInt。

Scala 系列(十三)—— 隐式转换和隐式参数

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpxjd.html