小编典典

理解 Scala 中的隐式

all

我正在阅读 Scala playframework 教程,我遇到了这段让我感到困惑的代码片段:

def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
        errors => BadRequest(views.html.index(Task.all(), errors)),
        label => {
          Task.create(label)
          Redirect(routes.Application.tasks())
        } 
  )
}

所以我决定调查并遇到这个帖子

我还是不明白。

这有什么区别:

implicit def double2Int(d : Double) : Int = d.toInt

def double2IntNonImplicit(d : Double) : Int = d.toInt

除了显而易见的事实之外,它们具有不同的方法名称。

我应该什么时候使用implicit,为什么?


阅读 69

收藏
2022-04-08

共1个答案

小编典典

我将在下面解释隐式的主要用例,但更多详细信息请参见Programming in Scala
的相关章节

隐式参数

方法的最终参数列表可以标记为implicit,这意味着值将从调用它们的上下文中获取。如果范围内没有正确类型的隐式值,则不会编译。由于隐式值必须解析为单个值并避免冲突,因此最好使类型特定于其用途,例如,不要求您的方法找到隐式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需要 an 并且它找到 a
B,它将B => A在范围内查找类型的隐式值(它还会检查其他一些地方,比如在BA伴随对象中,如果它们存在的话)。由于defs
可以“扩展”为Function对象,因此 animplicit def xyz(arg: B): A也可以。

因此,您的方法之间的区别在于,当找到 a 但需要 animplicit时,编译器将为您插入标记的方法。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对象上(这是同名特征的伴侣)。

所以我们需要提供一个函数作为参数,它可以写成如下形式的文字

request => ...

在函数字面量中,前面的部分=>是值声明,可以根据需要进行标记implicit,就像在任何其他val声明中一样。在这里,request
不必implicit为 this 进行类型检查,但通过这样做,它 可以作为函数中可能需要它的任何方法的隐式值 使用(当然,它也可以显式使用).
在这种特殊情况下,这样做是因为FormbindFromRequest类上的方法需要一个隐式参数。Request

2022-04-08