为什么在Scala中需要隐式参数?

Cha*_*ieQ 4 scala akka

我是scala的新手,今天,当我遇到此akka 源代码时,我感到困惑:

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 }
    }
  }
Run Code Online (Sandbox Code Playgroud)

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

scala.collection.JavaConversions.iterableAsScalaIterable(in).foldLeft(
  Future(new JLinkedList[B](),executor))
Run Code Online (Sandbox Code Playgroud)

是否不对新的隐式变量进行标量d?这样做有什么好处吗?目前,我仅发现隐式会增加代码的歧义。

sen*_*nia 5

我可以给你3个理由。

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...
Run Code Online (Sandbox Code Playgroud)

使用隐式参数:

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

情况还不错,但是如果您需要2个期货怎么办:

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

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

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

3.5)隐式参数允许进行类型级编程。见无形

关于“代码的歧义”:

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

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

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

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

  • 看看[typeclass](http://stackoverflow.com/a/5426131/406435)。它允许您添加行为而不继承。建议使用隐式参数。您问题中的“未来”使用了某种“上下文”。创建此类“上下文”是隐式参数的常见用法。 (3认同)

ghi*_*hik 3

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

所以我想说,在您链接的代码中,使用隐式参数只是为了遵循某种代码风格。破例是很难看的。