Scala:将字符串转换为 lambda

Da *_*ike 0 reflection lambda scala

我希望能够解析字符串"x => x + 1",并能够实际将其用作 lambda 函数,如下所示:

    val string = "x => x + 1"
    val lambda = parseLambda(string)
    val numbers = List(1, 2, 3)
    val result = numbers.map(lambda) // Should be [2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

我对该函数有以下实现parseLambda

  def parseLambda(string: String): Any => Any = {
      val toolbox = runtimeMirror(getClass.getClassLoader).mkToolBox()
      val tree = toolbox.parse(string)
      val lambdaFunction = toolbox.compile(tree)().asInstanceOf[Any => Any]
      lambdaFunction
  }
Run Code Online (Sandbox Code Playgroud)

它适用于像"(x: Int) => x * 2"or这样的字符串"(s: String) => s.split(" ")",但如果我省略类型,例如"x => x * 2"or"s => s.split(" ")"我会收到以下错误

';' expected but '=>' found.
Run Code Online (Sandbox Code Playgroud)

有没有办法能够省略字符串中的类型?任何帮助,将不胜感激!

Mat*_*zok 6

如果没有类型提示,则在 Scala 2 ( https://scastie.scala-lang.org/ChqbxOxRSvGhFTsXeyhOWA ) 和 Scala 3 ( https://scastie.scala-lang.org/1uYVoRXLTeKEwfoPCwrKzQx => x * 2 )中都无法编译。这根本就是糟糕的代码。返回相当无用的消息,但是编译器没有神奇的方法可以猜测输入应该是什么。toolkit.parse

然而,在您的代码中,有一些东西知道类型应该是什么:numbers.

trait TypeName[A] {
  def name: String
}

def parseLambda[Input: TypeName](string: String): Input => Any = {
  val code = s"""val result: ${implicitly[TypeName[Input]].name} => Any = ${string}
                |result
                |""".stripMargin
  val toolbox = runtimeMirror(getClass.getClassLoader).mkToolBox()
  val tree = toolbox.parse(code)
  val lambdaFunction = toolbox.compile(tree)().asInstanceOf[Input => Any]
  lambdaFunction
}
Run Code Online (Sandbox Code Playgroud)

然后它应该可以工作:

val string = "x => x + 1"
val lambda = parseLambda[Int](string) // Int hinted
val numbers = List(1, 2, 3)
val result = numbers.map(lambda) // Should be [2, 3, 4]

// or

numbers.map(parseLambda(string)) // Int inferred 
Run Code Online (Sandbox Code Playgroud)

也就是说,只要您提供正确的TypeName[A]实例,它就应该可以工作。

在 Scala 2 中,它应该与类似的东西一起工作:

object TypeName {

  import scala.reflect.runtime.universe._

  implicit def provide[A](implicit tag: WeakTypeTag[A]): TypeName[A] =
    new TypeName[A] {
      def name: String = tag.toString() // should work for simple cases
    }
}
Run Code Online (Sandbox Code Playgroud)

对于 Scala 3(您的代码看起来像 Scala 2,但如果您想将其移植到 3),类似于:

object TypeName {

  import scala.quoted.*
  
  def provideImpl[A: Type](using quotes: Quotes): Expr[TypeName[A]] =
    import quotes.*, quotes.reflect.*
    '{
      new TypeName[A] {
        def name: String = ${ TypeRepr.of[A].show(using TypeReprCode) }
      }
    }

  inline given provide[A]: TypeName[A] = ${ TypeName.provideImpl[A] }
}
Run Code Online (Sandbox Code Playgroud)

(免责声明,我还没有编译它,所以它应该是类似的东西,但可能需要一些调整)。

如果因为您不知道而无法提供该类型怎么办?(例如,如果这个 lambda 发送给您?)

好吧,如果您不知道类型编译器也不会知道,所以您根本无法这样做。