我在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]](x)
意味着我们用参数调用 implicitly
.
另见How to investigate objects/types/etc. from Scala REPL?和Where does Scala look for implicits?
3 回答
以下是使用令人愉快的简单方法
implicitly
的几个原因 .了解/排除隐式视图故障
选择前缀时可以触发隐式视图(例如,
the.prefix.selection(args)
不包含适用于args
的成员selection
(即使在尝试使用隐式视图转换args
之后) . 在这种情况下,编译器会查找隐式成员,在当前或封闭的作用域中本地定义,继承或导入,是从the.prefix
的类型到具有selection
定义的类型的函数,或等效的隐式方法 .当表达式不符合预期类型时,也可以触发隐式视图,如下所示:
这里编译器查找此函数:
访问由上下文绑定引入的隐式参数
隐式参数可以说是Scala比隐式视图更重要的特性 . 它们支持类型类模式 . 标准库在几个地方使用它 - 请参阅
scala.Ordering
以及如何在SeqLike#sorted
中使用它 . 隐式参数也用于传递数组清单和CanBuildFrom
实例 .Scala 2.8允许隐式参数的简写语法,称为Context Bounds . 简而言之,一个类型参数为
A
的方法需要一个类型为M[A]
的隐式参数:可以改写为:
但传递隐式参数但没有命名的重点是什么?在实现方法
foo
时,这怎么有用?通常,隐式参数不需要直接引用,它将作为另一个被调用方法的隐式参数进行隧道传输 . 如果需要,您仍然可以使用Context Bound保留简洁方法签名,并调用
implicitly
以实现该值:显式传递隐式参数的子集
假设您使用基于类型的方法调用一个非常打印人的方法:
如果我们想要改变名称输出的方式怎么办?我们可以显式调用
PersonShow
,显式传递一个替代Show[String]
,但我们希望编译器传递Show[Int]
.Implicitly
在Scala 2.8中可用,并在Predef中定义为:如果是这种情况,它通常用于 check if an implicit value of type T is available and return it .
来自retronym's presentation的简单示例:
"teach you to fish"答案是使用Scaladoc nightlies中当前可用的字母成员索引 . 包/类窗格顶部的字母(和非字母名称的
#
)是指向以该字母开头的成员名称索引的链接(跨所有类) . 如果您选择I
,例如,您将在Predef
中找到一次出现的implicitly
条目,您可以从该链接访问该条目 .