Scala标识符“隐式"是什么? [英] What is the Scala identifier "implicitly"?

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

问题描述

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

I have seen a function named implicitly used in Scala examples. What is it, and how is it used?

此处的示例:

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]](x)意味着我们使用参数调用implicitly,因此必须编写implicitly[Foo[A]].apply(x).

Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.

另请参阅如何调查对象/类型/等. Scala在哪里寻找隐式?

推荐答案

以下是使用令人愉快的简单方法implicitly的一些原因.

Here are a few reasons to use the delightfully simple method implicitly.

这是隐观可以被触发时,选择的前缀(例如,考虑不包含成员<6>是适用于<7>(甚至试图转换与隐意见后, ).在这种情况下,编译器将查找在当前作用域或封闭作用域中本地定义,继承或导入的隐式成员,这些成员是从the.prefix类型到定义为selection的类型的函数,或等效的隐式方法.

An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args) does not contain a member selection that is applicable to args (even after trying to convert args with 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.prefix to a type with selection defined, or equivalent implicit methods.

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>

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

隐式参数可以说是Scala比隐式视图更重要的功能.它们支持类型类模式.标准库在几个地方使用了它-请参见scala.Ordering及其在SeqLike#sorted中的用法.隐式参数还用于传递数组清单和CanBuildFrom实例.

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.Ordering and how it is used in SeqLike#sorted. Implicit Parameters are also used to pass Array manifests, and CanBuildFrom instances.

Scala 2.8允许使用隐式参数的快捷语法,称为Context Bounds.简要地讲,类型参数为A的方法需要类型为M[A]的隐式参数:

Scala 2.8 allows a shorthand syntax for implicit parameters, called Context Bounds. Briefly, a method with a type parameter A that requires an implicit parameter of type M[A]:

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

可以改写为:

def foo[A: M]

但是传递隐式参数但不命名它又有什么意义呢?在实现方法foo时如何使用?

But what's the point of passing the implicit parameter but not naming it? How can this be useful when implementing the method foo?

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

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 implicitly to materialize the value:

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)

如果我们想更改名称输出的方式怎么办?我们可以显式调用PersonShow,显式地传递替代项Show[String],但是我们希望编译器传递Show[Int].

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

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

这篇关于Scala标识符“隐式"是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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