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

我已经看到一个名为在Scala示例中implicitly使用的函数。 它是什么,它是如何使用的?

示例:

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调用。

另请参阅如何调查对象/类型/等。 来自Scala REPL? Scala在哪里寻找隐含?


以下是implicitly使用令人愉快的简单方法的几个原因。

了解/排除隐式视图

当选择的前缀(例如, the.prefix.selection(args)不包含适用于args的成员selection (甚至在尝试使用Implicit Views转换args之后the.prefix.selection(args)时,可以触发Implicit View)。在此情况下,编译器会查找隐式成员,这些隐式成员在当前或封闭作用域中本地定义的,被继承或导入的,既可以是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

当表达式不符合预期类型时,也可以触发隐式视图,如下所示:

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更重要的特性。 他们支持类型模式。 标准库在几个地方使用它 - 请参阅scala.Ordering以及它如何在SeqLike#sorted 。 隐式参数也用于传递Array清单和CanBuildFrom实例。

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

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

可以改写为:

def foo[A: M]

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

通常,隐式参数不需要直接引用,它将通过作为隐式参数的隧道传递给另一个被调用的方法。 如果需要,您仍然可以使用Context Bound保留简洁方法签名,并implicitly调用以实现该值:

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

显式传递隐式参数的子集

假设您使用基于类型类的方法调用可以打印人物的方法:

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)

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

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

它通常用于检查类型T的隐式值是否可用并返回它,如果是这种情况。

来自反义词的简单例子:

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

一个“教你钓鱼”的答案是使用斯卡拉多克斯当前可用的字母成员索引。 封装/类窗格顶部的字母(以及#对于非字母名称)是指向以该字母开头的成员名称(跨所有类)的索引的链接。 如果您选择I ,例如,您可以在Predef找到implicitly条目,但您可以从该链接访问该条目。

链接地址: http://www.djcxy.com/p/72811.html

上一篇: What is the Scala identifier "implicitly"?

下一篇: Scala @ operator