理解 Scala 中的隐式 [英] Understanding implicit in Scala
问题描述
我在学习 Scala playframework 教程时遇到了这段让我感到困惑的代码片段:
def newTask = Action { 隐式请求 =>taskForm.bindFromRequest.fold(错误 =>BadRequest(views.html.index(Task.all(), errors)),标签 =>{任务.创建(标签)重定向(routes.Application.tasks())})}
所以我决定进行调查并发现了这篇文章.>
我还是不明白.
这有什么区别:
implicit def double2Int(d : Double) : Int = d.toInt
和
def double2IntNonImplicit(d : Double) : Int = d.toInt
除了显而易见的事实之外,它们具有不同的方法名称.
什么时候应该使用 implicit
以及为什么?
我将在下面解释隐式的主要用例,但更多细节参见 Scala 编程的相关章节.
隐式参数
方法的最终参数列表可以标记为implicit
,这意味着这些值将从调用它们的上下文中获取.如果作用域中没有正确类型的隐式值,它将不会编译.由于隐式值必须解析为单个值并避免冲突,因此最好使类型特定于其目的,例如不需要您的方法来查找隐式 Int
!
示例:
//可能在一个库中类前缀(val前缀:字符串)def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s//那么可能在你的应用程序中隐式 val myImplicitPrefixer = new Prefixer("***")addPrefix("abc")//返回 "***abc"
隐式转化
当编译器为上下文找到错误类型的表达式时,它将寻找一个隐式的 Function
类型值,以允许它进行类型检查.因此,如果需要 A
并且找到 B
,它将查找 B => 类型的隐式值.A
范围内(它还检查其他一些地方,如 B
和 A
伴随对象,如果它们存在).由于 def
s 可以eta-expanded"到 Function
对象中,隐式 def xyz(arg: B): A
也可以.
因此,您的方法之间的区别在于,当找到 Double
但Int时,编译器将为您插入标记为
implicit
的方法代码> 是必需的.
implicit def doubleToInt(d: Double) = d.toIntval x: 整数 = 42.0
将与
相同def doubleToInt(d: Double) = d.toIntval x: Int = doubleToInt(42.0)
在第二个中,我们手动插入了转换;首先,编译器会自动执行相同的操作.由于左侧的类型注释,需要进行转换.
<小时>关于你的第一个 Play 片段:
操作在 此页面上从 Play 文档中进行了解释(另请参阅API 文档).您正在使用
apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]
在 Action
对象上(它是同名 trait 的伴侣).
所以我们需要提供一个Function作为参数,它可以写成如下形式的文字
request =>...
在函数字面量中,=>
之前的部分是一个值声明,如果需要,可以标记为 implicit
,就像在任何其他 中一样>val
声明.在这里,request
不必被标记为implicit
以便进行类型检查,但这样做后它可以作为函数中可能需要它的任何方法的隐式值(当然,它也可以显式使用).在这种特殊情况下,这是因为 Form 类需要一个隐式的 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 def
s 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屋!