了解Scala中的隐式 [英] Understanding implicit in Scala

查看:89
本文介绍了了解Scala中的隐式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在遍历Scala播放框架教程,并且遇到了使我感到困惑的这段代码:

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,为什么?

解决方案

我将在下面解释隐式的主要用例,但有关更多详细信息,请参见

隐式转换

当编译器为上下文找到错误类型的表达式时,它将查找类型的隐式Function值,该值将允许其进行类型检查.因此,如果需要A并找到B,它将在范围内查找类型为B => A的隐式值(它还会检查其他地方,例如BA随播对象, (如果存在).由于def可以扩展"为Function对象,因此implicit def xyz(arg: B): A也可以.

因此,您的方法之间的区别在于,当找到Double但需要Int时,编译器将为您插入标记为implicit的方法.

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]

对象上的

(同名特征的伴侣).

因此,我们需要提供一个Function作为参数,可以将其写为

request => ...

在函数文字中,=>之前的部分是值声明,并且可以将其标记为implicit,就像在其他任何val声明中一样.在这里,不必request 标记为implicit来进行类型检查,但是这样做可以将用作任何方法的隐式值函数中可能需要它(当然,也可以显式使用它).在此特定情况下,已完成此操作,因为bindFromRequest方法. html"rel =" noreferrer>表单类需要隐式的Request参数.

I was making my way through the Scala playframework tutorial and I came across this snippet of code which had me puzzled:

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

So I decided to investigate and came across this post.

I still don't get it.

What is the difference between this:

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

and

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

other than the obvious fact they have different method names.

When should I use implicit and why?

解决方案

I'll explain the main use cases of implicits below, but for more detail see the relevant chapter of Programming in Scala.

Implicit parameters

The final parameter list on a method can be marked implicit, which means the values will be taken from the context in which they are called. If there is no implicit value of the right type in scope, it will not compile. Since the implicit value must resolve to a single value and to avoid clashes, it's a good idea to make the type specific to its purpose, e.g. don't require your methods to find an implicit Int!

example:

  // 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"

Implicit conversions

When the compiler finds an expression of the wrong type for the context, it will look for an implicit Function value of a type that will allow it to typecheck. So if an A is required and it finds a B, it will look for an implicit value of type B => A in scope (it also checks some other places like in the B and A companion objects, if they exist). Since defs can be "eta-expanded" into Function objects, an implicit def xyz(arg: B): A will do as well.

So the difference between your methods is that the one marked implicit will be inserted for you by the compiler when a Double is found but an Int is required.

implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0

will work the same as

def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)

In the second we've inserted the conversion manually; in the first the compiler did the same automatically. The conversion is required because of the type annotation on the left hand side.


Regarding your first snippet from Play:

Actions are explained on this page from the Play documentation (see also API docs). You are using

apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]

on the Action object (which is the companion to the trait of the same name).

So we need to supply a Function as the argument, which can be written as a literal in the form

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.

这篇关于了解Scala中的隐式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆