【问题标题】:Why we need implicit parameters in scala?为什么我们需要 scala 中的隐式参数?
【发布时间】:2012-12-11 01:45:04
【问题描述】:

我是scala的新手,今天遇到这个akkasource 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?这样做有什么好处吗?现在我只发现隐式增加了代码的歧义。

【问题讨论】:

    标签: scala akka


    【解决方案1】:

    我可以给你 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) 它允许您使用泛型方法创建 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

    关于“代码的歧义”:

    您不必使用隐式,或者您可以显式指定所有参数。有时它看起来很难看(参见 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)

    【讨论】:

    • 隐式很强大,但是如果它把一种语言变成一种程序员的方言,那就很难理解了,尤其是当你需要更多的人来编写成千上万的代码时。 scala 是否有任何关于创建隐式的规则?
    • 看看typeclass。它允许您在没有继承的情况下添加行为。这是隐式参数的推荐用法。您的问题中的Future 使用了某种“上下文”。创建此类“上下文”是隐式参数的常见用法。
    • 谢谢,这个链接很有用
    【解决方案2】:

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

    所以我想说,在你链接的代码中,隐式参数只是为了遵循一些代码风格。例外是很难看的。

    【讨论】:

      【解决方案3】:

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

      什么是隐式参数?

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

      为什么要使用隐式参数?

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-09
        • 1970-01-01
        • 2018-09-22
        • 2017-01-20
        相关资源
        最近更新 更多