什么是Scala标识符“隐含”?

我已经看到一个名字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$1: 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)) ^ 

注意,我们必须implicitly[Foo[A]].apply(x)地写implicitly[Foo[A]].apply(x)因为编译器认为implicitly[Foo[A]](x)意味着我们用参数implicitly调用。

另请参阅如何调查对象/types/等。 来自Scala REPL? Scala在哪里寻找implicits?

这里有一些implicitly使用令人愉快的简单方法的原因。

了解/疑难解答隐式视图

当select的前缀(例如, the.prefix.selection(args)不包含适用于args的成员selection (甚至在尝试使用隐式视图转换args之后the.prefix.selection(args)时,可以触发Implicit View)。情况下,编译器会查找隐式成员,这些隐式成员是在当前或封闭作用域中本地定义的,被inheritance或导入的隐式成员,既可以是从the.prefixtypes定义的函数,也可以是等价的隐式方法。

 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 

隐式视图也可以在expression式不符合预期types时触发,如下所示:

 scala> 1: scala.runtime.RichInt res25: scala.runtime.RichInt = 1 

这里编译器查找这个函数:

 scala> implicitly[Int => scala.runtime.RichInt] res26: (Int) => scala.runtime.RichInt = <function1> 

访问由上下文绑定引入的隐式参数

隐式参数可以说是Scala比Implicit Views更重要的特性。 他们支持types模式。 标准库在几个地方使用这个 – 请参阅scala.Ordering以及SeqLike#sorted如何使用它。 隐式参数也用于传递数组清单和CanBuildFrom实例。

Scala 2.8允许隐式参数的简写语法,称为上下文边界。 简而言之,使用types参数A的方法需要M[A]types的隐式参数:

 def foo[A](implicit ma: M[A]) 

可以改写为:

 def foo[A: M] 

但是传递隐式参数的意义是什么,却没有命名呢? 如何在执行foo方法时有用?

通常隐式参数不需要直接引用,而是通过隐式parameter passing给另一个被调用的方法。 如果需要的话,仍然可以使用Context Bound保留简洁的方法签名,并implicitly调用以实现该值:

 def foo[A: M] = { val ma = implicitly[M[A]] } 

显式传递隐式参数的子集

假设你正在调用一个可以打印一个人的方法,使用一个基于types的方法:

 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) 

如果我们想改变名称的输出方式呢? 我们可以显式调用PersonShow ,显式传递一个替代的Show[String] ,但我们希望编译器通过Show[Int]

 Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p) 

在Scala 2.8中Implicitly是可用的,在Predef中定义为:

 def implicitly[T](implicit e: T): T = e 

它通常用于检查typesT的隐式是否可用,如果是返回它

简单的例子来自retrony的介绍 :

 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] ^ 

一个“教你钓鱼”的答案是使用Scaladoc nightlies目前可用的字母成员索引。 封装/类窗格顶部的字母(和非字母名称的# )是指向以该字母开头(跨所有类)的成员名称的索引的链接。 如果你select了I ,例如,你可以在Predeffind一个implicitly条目,你可以通过链接访问它。