什么是 Scala 标识符“隐式”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3855595/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the Scala identifier "implicitly"?
提问by oluies
I have seen a function named implicitlyused in Scala examples. What is it, and how is it used?
我implicitly在 Scala 示例中看到了一个名为的函数。它是什么,如何使用?
scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
Foo[Double]
foo(List(1.0))
^
Note that we have to write implicitly[Foo[A]].apply(x)since the compiler thinks that implicitly[Foo[A]](x)means that we call implicitlywith parameters.
请注意,我们必须编写,implicitly[Foo[A]].apply(x)因为编译器认为这 implicitly[Foo[A]](x)意味着我们implicitly使用参数进行调用。
Also see How to investigate objects/types/etc. from Scala REPL?and Where does Scala look for implicits?
回答by oluies
Implicitlyis avaliable in Scala 2.8 and is defined in Predefas:
Implicitly在 Scala 2.8 中可用,并在Predef 中定义为:
def implicitly[T](implicit e: T): T = e
It is commonly used to check if an implicit valueof type Tis available and return itif such is the case.
它通常用于检查类型的隐式值T是否可用,如果是,则返回它。
Simple example from retronym's presentation:
来自retronym 的演示的简单示例:
scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
val c = implicitly[Int]
^
回答by retronym
Here are a few reasons to use the delightfully simple method implicitly.
以下是使用令人愉快的简单方法的几个原因implicitly。
To understand/troubleshoot Implicit Views
了解/排除隐式视图的故障
An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args)does not contain a member selectionthat is applicable to args(even after trying to convert argswith Implicit Views). In this case, the compiler looks for implicit members, locally defined in the current or enclosing scopes, inherited, or imported, that are either Functions from the type of that the.prefixto a type with selectiondefined, or equivalent implicit methods.
An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args)does not contain a member selectionthat is applicable to args(even after trying to convert argswith Implicit Views). In this case, the compiler looks for implicit members, locally defined在当前或封闭的范围内,继承的或导入的,要么是从该类型the.prefix到具有selection定义的类型的函数,要么是等效的隐式方法。
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Implicit Views can also be triggered when an expression does not conform to the Expected Type, as below:
当表达式不符合预期类型时,也可以触发隐式视图,如下所示:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Here the compiler looks for this function:
编译器在这里寻找这个函数:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Accessing an Implicit Parameter Introduced by a Context Bound
访问由上下文绑定引入的隐式参数
Implicit parameters are arguably a more important feature of Scala than Implicit Views. They support the type class pattern. The standard library uses this in a few places -- see scala.Orderingand how it is used in SeqLike#sorted. Implicit Parameters are also used to pass Array manifests, and CanBuildFrominstances.
隐式参数可以说是 Scala 比隐式视图更重要的特性。它们支持类型类模式。标准库在几个地方scala.Ordering使用它- 请参阅以及如何在SeqLike#sorted. 隐式参数也用于传递数组清单和CanBuildFrom实例。
Scala 2.8 allows a shorthand syntax for implicit parameters, called Context Bounds. Briefly, a method with a type parameter Athat requires an implicit parameter of type M[A]:
Scala 2.8 允许隐式参数的速记语法,称为上下文边界。简而言之,具有类型参数的方法A需要类型为隐式参数M[A]:
def foo[A](implicit ma: M[A])
can be rewritten as:
可以改写为:
def foo[A: M]
But what's the point of passing the implicit parameter but not naming it? How can this be useful when implementing the method foo?
但是传递隐式参数而不命名它有什么意义呢?这在实施该方法时foo有何用处?
Often, the implicit parameter need not be referred to directly, it will be tunneled through as an implicit argument to another method that is called. If it is needed, you can still retain the terse method signature with the Context Bound, and call implicitlyto materialize the value:
通常,不需要直接引用隐式参数,它将作为隐式参数传递给另一个被调用的方法。如果需要,您仍然可以保留带有 Context Bound 的简洁方法签名,并调用implicitly以实现该值:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Passing a subset of implicit parameters explicitly
显式传递隐式参数的子集
Suppose you are calling a method that pretty prints a person, using a type class based approach:
假设您正在使用基于类型类的方法调用一个可以漂亮地打印一个人的方法:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
What if we want to change the way that the name is output? We can explicitly call PersonShow, explicitly pass an alternative Show[String], but we want the compiler to pass the Show[Int].
如果我们想改变名字的输出方式怎么办?我们可以显式调用PersonShow,显式传递一个替代项Show[String],但我们希望编译器传递Show[Int].
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
回答by Randall Schulz
A "teach you to fish" answer is to use the alphabetic member index currently available in the Scaladoc nightlies. The letters (and the #, for non-alphabetic names) at the top of the package / class pane are links to the index for member names beginning with that letter (across all classes). If you choose I, e.g., you'll find the implicitlyentry with one occurrence, in Predef, which you can visit from the link there.
“教你钓鱼”的答案是使用当前在Scaladoc nightlies 中可用的字母成员索引。#包/类窗格顶部的字母(和, 表示非字母名称)是指向以该字母开头的成员名称(跨所有类)的索引的链接。I例如,如果您选择,您会在 中找到implicitly出现一次的条目Predef,您可以从那里的链接访问该条目。

