2012-12-11 55 views
3

我是新来斯卡拉,今天,当我遇到这个阿卡source code我很困惑就来了:为什么我们需要scala中的隐式参数?

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)) 

没有decalaring一个新的隐式变量d?这样做有什么好处吗?现在我只发现隐含增加了代码的不明确性。

回答

3

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

所以我想说,在你链接的代码中,隐式参数只是用来跟随一些代码风格。从它那里破例是难以置信的。

1

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

什么是隐式参数?

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

为什么使用隐式参数?

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

4

我可以给你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... 

使用隐式参数:

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

2)alows您创建泛型方法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)

+0

隐含是强大的,但如果它将语言变成一种程序员的方言,它将很难理解,特别是当你需要更多的人编写数千个代码时。 scala是否有创建含义的规则? – CharlieQ

+3

看看[typeclass](http://stackoverflow.com/a/5426131/406435)。它允许你在没有继承的情况下添加行为。这是推荐使用隐式参数。你的问题中的“未来”使用某种“背景”。创建这样的“上下文”是隐式参数的常见用法。 – senia

+0

谢谢,这个链接很有用 – CharlieQ