【问题标题】:Scala Implicit conversion for LambdasLambda 的 Scala 隐式转换
【发布时间】:2018-09-16 09:14:43
【问题描述】:

我正在尝试从链接中了解隐式函数类型 - http://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html,下面是示例代码作为示例。在下面的代码中,我们首先创建了一个 Transaction 类。

class Transaction {
  private val log = scala.collection.mutable.ListBuffer.empty[String]
  def println(s: String): Unit = log += s

  private var aborted = false
  private var committed = false

  def abort(): Unit = { aborted = true }
  def isAborted = aborted

  def commit(): Unit =
  if (!aborted && !committed) {
     Console.println("******* log ********")
     log.foreach(Console.println)
     committed = true
  }
}

接下来我定义两个方法 f1 和 f2 如下所示

def f1(x: Int)(implicit thisTransaction: Transaction): Int = {
  thisTransaction.println(s"first step: $x")
  f2(x + 1)
}
def f2(x: Int)(implicit thisTransaction: Transaction): Int = {
  thisTransaction.println(s"second step: $x")
  x
}

然后定义一个方法来调用函数

def transaction[T](op: Transaction => T) = {
  val trans: Transaction = new Transaction
  op(trans)
  trans.commit()
}

下面的lambda用于调用代码

transaction {
    implicit thisTransaction =>
      val res = f1(3)
      println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
}  

我的问题是如果我将val trans: Transaction = new Transaction 更改为implicit val thisTransaction = new Transaction 并将op(trans) 更改为op 它不起作用。

我无法理解为什么即使 Transaction 类型的 thisTransaction 存在于它没有被使用的范围内?

【问题讨论】:

    标签: scala lambda dotty scala-3


    【解决方案1】:

    未来版本的 Scala 计划使用隐式函数类型。据我所知,甚至下一个版本(2.13)都没有。

    目前,您只能在Dotty 中使用它们。

    【讨论】:

      【解决方案2】:

      这里用dotty 0.4.0-RC1编译得很好:

      def transaction[T](op: implicit Transaction => T) = {
        implicit val trans: Transaction = new Transaction
        op
        trans.commit()
      }
      

      我认为从博客文章的介绍中应该清楚,这是 Odersky 发明的一个新功能,用于消除 Dotty 编译器实现中的一些样板,引用:

      例如在 dotty 编译器中,几乎每个函数都采用隐式上下文参数,该参数定义与当前编译状态相关的所有元素。

      目前主流版本的Scala似乎没有这个功能。


      编辑

      (回答评论中的后续问题)

      如果我对博客文章的理解正确,它就会被脱糖成类似

      transaction(
        new ImplicitFunction1[Transaction, Unit] {
          def apply(implicit thisTransaction: Transaction): Unit = {
            val res = f1(args.length)(implicit thisTransaction:Transaction) 
            println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
          }
        } 
      )
      

      new ImplicitFunction1[...]{} 是一个匿名本地类。基类ImplicitFunction1 就是这个新特性,它类似于普通lambda 的Function,但带有implicit 参数。

      【讨论】:

      • 如果transaction { implicit thisTransaction => val res = f1(3) println(if (thisTransaction.isAborted) "aborted" else s"result: $res") } 被翻译成transaction { anon_lambda( thisTransaction => val res = f1(args.length)(implicit thisTransaction:Transaction) println(if (thisTransaction.isAborted) "aborted" else s"result: $res")) } ,请告诉我。希望我的问题很清楚
      • @jjayadeep 在我的回答中添加了一个可能的去糖块。
      【解决方案3】:

      opTransaction => T 类型,而不是 implicit Transaction => T(我认为不可能指定它,不幸的是)。

      所以它的Transaction 类型的参数不能被隐式提供。它必须是一个显式参数。 (只能隐式提供标记为 implicit 的参数列表中的函数的参数。)

      【讨论】:

      • “不幸的是,我认为不可能指定这一点”还没有
      • @AlexeyRomanov "yet" 过分强调时间方面。实际上,它已经实现了,但是在不同的 Scala 编译器中(例如,它适用于 dotty 0.4.x)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-01
      • 2019-04-01
      • 1970-01-01
      • 2012-04-15
      • 2011-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多