从Scala函数到Java函数

时间:2016-04-24 19:45:20

标签: java scala implicit-conversion type-inference

我想创建一个从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"

编译器能够推断出类型

我的问题是:

  • 为什么Scala编译器在第三种情况下不能推断出参数的类型?
  • 我可以修改隐式转换,以便推断出类型吗?

我知道有related question涉及此主题,但没有回答我的问题。

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

2 个答案:

答案 0 :(得分:3)

  

为什么Scala编译器在第三种情况下不能推断出参数的类型?

要推断lambda表达式的参数类型,期望类型必须是String => ?(对于这种情况)。在converted3中,预期类型为JavaFunction[String, Int]。这不是Scala函数,所以它不会起作用。它在Scala 2.12中,或在2.11中与-Xexperimental scalac option。这是根据the specification

  
    

如果匿名函数的预期类型是scala.Functionn [S1,...,Sn,R]形状,或者可以SAM转换为这样的函数类型,则类型     钛      一个参数     喜      可以省略,至于     硅      在预期的类型中定义,和     钛      =     硅      假设。此外,类型检查时的预期类型     Ë      是     R上。

         

如果函数文字没有预期的类型,则必须显式指定所有形式参数类型Ti,并且未定义e的预期类型。

  
" SAM转换" part是由-Xexperimental / 2.12激活的,默认情况下在2.11中无效。

  

我可以修改隐式转换,以便推断出类型吗?

我不相信。您可以做的是更改地点转换:写val unconverted: String => Int = s => s.toInt(或只是val unconverted = (s: String) => s.toInt)并将其传递到预期JavaFunction[String, Int]的位置。

答案 1 :(得分:1)

当你编写val foo: SomeType = bar时,编译器正在寻找一种“证明”的方法,即赋值是有效的。这可以通过以下两种方式之一来证明:bar有一个类型,它是SomeType的子类(或显然是SomeType本身)或者是任何类型的隐式转换{ {1}}是bar。 正如你可以看到的那样,在两种情况下,对于工作的辅助,必须知道SomeType的类型。但是当你写bar时,右边的类型没有定义。编译器知道它是一些函数,返回一个Int,但没有参数类型,这还不够。

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

AFAIK无法绕过它,你必须以某种方式定义rhs的类型才能使用隐式转换。