为什么我们需要scala中的隐式参数?

时间:2012-12-11 01:45:05

标签: scala akka

我是scala的新手,今天当我遇到这个akka时source code我很困惑:

def traverse[A, B](in: JIterable[A], fn: JFunc[A, Future[B]], 
      executor: ExecutionContext): Future[JIterable[B]] = {
    implicit val d = executor
    scala.collection.JavaConversions.iterableAsScalaIterable(in).foldLeft(
        Future(new JLinkedList[B]())) { (fr, a) ⇒
      val fb = fn(a)
      for (r ← fr; b ← fb) yield { r add b; r }
    }
  }

为什么有意使用隐式参数编写代码?为什么不能写成:

scala.collection.JavaConversions.iterableAsScalaIterable(in).foldLeft(
  Future(new JLinkedList[B](),executor))

没有声明一个新的隐式变量d?这样做有什么好处吗?现在我只发现implicits会增加代码的模糊性。

3 个答案:

答案 0 :(得分:4)

我可以给你三个理由。

1)它隐藏了样板代码。

让我们对一些列表进行排序:

import math.Ordering

List(1, 2, 3).sorted(Ordering.Int) // Fine. I can tell compiler how to sort ints
List("a", "b", "c").sorted(Ordering.String) // .. and strings.
List(1 -> "a", 2 -> "b", 3 -> "c").sorted(Ordering.Tuple2(Ordering.Int, Ordering.String)) // Not so fine...

使用隐式参数:

List(1, 2, 3).sorted // Compiller knows how to sort ints
List(1 -> "a", 2 -> "b", 3 -> "c").sorted // ... and some other types

2)它允许您使用通用方法创建API:

scala> (70 to 75).map{ _.toChar }
res0: scala.collection.immutable.IndexedSeq[Char] = Vector(F, G, H, I, J, K)

scala> (70 to 75).map{ _.toChar }(collection.breakOut): String // You can change default behaviour.
res1: String = FGHIJK

3)它可以让你专注于真正重要的事情:

Future(new JLinkedList[B]())(executor) // meters: what to do - `new JLinkedList[B]()`. don't: how to do - `executor`

这不是很糟糕,但如果你需要2个期货怎么办:

val f1 = Future(1)(executor)
val f2 = Future(2)(executor) // You have to specify the same executor every time.

隐式为所有操作创建“上下文”:

implicit val d = executor // All `Future` in this scope will be created with this executor.
val f1 = Future(1)
val f2 = Future(2)

3.5)隐式参数允许类型级编程。请参阅shapeless

关于“代码含糊不清”:

您不必使用implicits,也可以显式指定所有参数。它有时看起来很丑陋(参见sorted示例),但你可以做到。

如果找不到哪些隐式变量用作参数,可以询问编译器:

>echo object Test { List( (1, "a") ).sorted } > test.scala
>scalac -Xprint:typer test.scala

您会在输出中找到math.this.Ordering.Tuple2[Int, java.lang.String](math.this.Ordering.Int, math.this.Ordering.String)

答案 1 :(得分:3)

在您链接的Akka代码中,确实可以只显式传递执行程序。但是如果在这个方法中使用了多个Future,那么声明隐式参数肯定是有意义的,以避免多次传递它。

所以我想说在您链接的代码中,隐式参数仅用于遵循一些代码样式。从中做出例外会很难看。

答案 2 :(得分:1)

你的问题引起了我的兴趣,所以我在网上搜索了一下。以下是我在此博客上发现的内容:http://daily-scala.blogspot.in/2010/04/implicit-parameters.html

什么是隐含参数?

  

隐式参数是标记为隐式的方法或构造函数的参数。这意味着如果未提供参数值,则编译器将搜索范围内定义的“隐式”值(根据解析规则。)

为什么要使用隐式参数?

  

隐式参数非常适合简化API。例如,集合使用隐式参数为许多集合方法提供CanBuildFrom对象。这是因为通常用户不需要关心那些参数。另一个例子是向IO库提供编码,因此编码定义一次(可能在包对象中),并且所有方法都可以使用相同的编码,而不必为每个方法调用定义它。