首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >什么是“隐式”的Scala标识符?

什么是“隐式”的Scala标识符?
EN

Stack Overflow用户
提问于 2010-10-04 21:22:00
回答 2查看 65K关注 0票数 174

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

Example here

代码语言:javascript
复制
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]](x)意味着我们使用参数调用implicitly

另请参阅How to investigate objects/types/etc. from Scala REPL?Where does Scala look for implicits?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-10-05 06:05:45

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

了解隐式视图/排除隐式视图的故障

隐式视图可以在选择的前缀时触发(例如,考虑the.prefix.selection(args)不包含适用于args的成员selection (即使在尝试使用隐式视图转换args之后)。在这种情况下,编译器查找隐式成员,这些隐式成员是在当前或封闭范围内本地定义的、继承的或导入的,这些隐式成员是从该the.prefix的类型到定义了selection的类型的函数,或者是等效的隐式方法。

代码语言:javascript
复制
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

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

代码语言:javascript
复制
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1

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

代码语言:javascript
复制
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>

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

隐式参数可以说是Scala比隐式视图更重要的特性。它们支持类型类模式。标准库在一些地方使用了它--请参阅scala.Ordering和如何在SeqLike#sorted中使用它。隐式参数还用于传递数组清单和CanBuildFrom实例。

Scala2.8允许隐式参数的简写语法,称为上下文界限。简而言之,具有类型参数A的方法需要类型为M[A]的隐式参数

代码语言:javascript
复制
def foo[A](implicit ma: M[A])

可以重写为:

代码语言:javascript
复制
def foo[A: M]

但是传递隐式参数而不命名它有什么意义呢?在实现方法foo时,这有什么用呢

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

代码语言:javascript
复制
def foo[A: M] = {
   val ma = implicitly[M[A]]
}

显式传递隐式参数子集

假设您正在调用一个方法,该方法使用基于类型类的方法漂亮地打印一个person:

代码语言:javascript
复制
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]

代码语言:javascript
复制
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
票数 210
EN

Stack Overflow用户

发布于 2010-10-04 21:50:19

一个“教你钓鱼”的答案是使用Scaladoc nightlies中目前可用的字母成员索引。包/类窗格顶部的字母(以及非字母名称的# )是指向以该字母开头的成员名称(跨所有类)的索引的链接。如果您选择I,例如,您将在Predef中找到具有一个匹配项的implicitly条目,您可以从那里的链接访问该条目。

票数 -4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3855595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档