从 Scala 函数到 Java 函数的隐式转换

Implicit conversion from Scala function to Java Function

我想创建一个从 Scala 函数(可能是匿名的)到 java.util.function.Function 的隐式转换。这是我拥有的:

import java.util.function.{Function => JavaFunction}
implicit def scalaFunctionToJavaFunction[From, To](function: (From) => To): JavaFunction[From, To] = {
  new java.util.function.Function[From, To] {
    override def apply(input: From): To = function(input)
  }
}

它工作正常,除了当被转换的函数没有明确指定参数类型时类型推断失败:

val converted: JavaFunction[String, Int] = (s: String) => s.toInt // works fine
val converted2: JavaFunction[String, Int] = scalaFunctionToJavaFunction(s => s.toInt) // works
val converted3: JavaFunction[String, Int] = s => s.toInt // gives compilation error "missing parameter type"

编译器能够推断类型

我的问题是:

我知道一个 涉及到这个主题,但没有回答我的问题。

这个问题似乎与 Java 的互操作性无关,顺便说一句。如果我用自定义 Scala 特征替换 JavaFunction,行为保持不变。

Why cannot Scala compiler infer type of the parameter in the third case?

要推断 lambda 表达式的参数类型,预期类型 必须是 String => ?(对于这种情况)。在 converted3 中,期望的类型是 JavaFunction[String, Int]。这不是一个 Scala 函数,所以它不会工作。它 在 Scala 2.12 中,或在 2.11 中 -Xexperimental scalac option. This is according to the specification:

If the expected type of the anonymous function is of the shape scala.Functionn[S1,…,Sn, R], or can be SAM-converted to such a function type, the type Ti of a parameter xi can be omitted, as far as Si is defined in the expected type, and Ti = Si is assumed. Furthermore, the expected type when type checking e is R.

If there is no expected type for the function literal, all formal parameter types Ti must be specified explicitly, and the expected type of e is undefined.

"SAM-converted"部分是由-Xexperimental/2.12激活的部分,默认情况下在2.11中无效。

Can I modify the implicit conversion so that the type gets inferred?

我不这么认为。您可以 做的是更改转换发生的位置:写入val unconverted: String => Int = s => s.toInt(或只是val unconverted = (s: String) => s.toInt)并将其传递到预期JavaFunction[String, Int] 的位置。

当你写 val foo: SomeType = bar 时,编译器正在寻找一种方法 "prove",以确保赋值有效。这可以通过以下两种方式之一来证明:bar 有一个类型,它是 SomeType 的子类(或者显然是 SomeType 本身),或者存在从任何类型的隐式转换 barSomeType。 正如你所看到的,在这两种情况下,为了使 assihnment 起作用,必须知道 bar 的类型。但是当你写 val converted3: JavaFunction[String, Int] = s => s.toInt 时,右侧的类型没有定义。编译器知道,它是某个函数,返回一个 Int,但没有参数类型,这是不够的。

另一种说法是,编译器不会检查范围内的每个隐式转换,返回与 LHS 兼容的内容,为了使用转换,它需要知道输入类型。

没有办法绕过它 AFAIK,您必须以一种或另一种方式定义 rhs 的类型才能使用隐式转换。