我将在下面解释隐式的主要用例,但要了解更多细节,请参阅Scala编程的相关章节。
隐式参数
方法的最后一个参数列表可以标记为隐式的,这意味着这些值将从调用它们的上下文中获取。如果作用域中没有正确类型的隐式值,则不会编译。因为隐式值必须解析为单个值,为了避免冲突,让类型特定于它的目的是一个好主意,例如,不需要你的方法找到一个隐式Int!
例子:
// probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s
// then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc") // returns "***abc"
隐式转换
当编译器为上下文找到错误类型的表达式时,它将寻找允许它进行类型检查的类型的隐式Function值。因此,如果A是必需的,并且它找到了B,它将在作用域中寻找类型为B => A的隐式值(它还检查其他一些地方,如B和A伴生对象,如果它们存在的话)。由于defs可以被“扩展”为Function对象,隐式def xyz(arg: B): A也可以。
因此,你的方法之间的区别是,标记为隐式的方法将被编译器插入,当你找到一个Double,但Int是必需的。
implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0
会和
def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)
在第二种方法中,我们手动插入转换;在第一种情况下,编译器自动执行相同的操作。转换是必需的,因为左边有类型注释。
关于Play的第一个片段:
在这个页面上,Play文档解释了操作(参见API文档)。你正在使用
apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]
Action对象(它是同名trait的同伴)。
所以我们需要提供一个Function作为参数,它可以写成这样的文字形式
request => ...
In a function literal, the part before the => is a value declaration, and can be marked implicit if you want, just like in any other val declaration. Here, request doesn't have to be marked implicit for this to type check, but by doing so it will be available as an implicit value for any methods that might need it within the function (and of course, it can be used explicitly as well). In this particular case, this has been done because the bindFromRequest method on the Form class requires an implicit Request argument.