简体   繁体   English

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

[英]Implicit conversion from Scala function to Java Function

I would like to create an implicit conversion from a Scala function (possibly anonymous) to java.util.function.Function . 我想创建一个从Scala函数(可能是匿名的)到java.util.function.Function的隐式转换。 Here is what I have: 这是我有的:

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)
  }
}

It works fine except that the type inference fails when the function being converted doesn't specify parameter type explicitly: 它工作正常,只是当转换的函数没有明确指定参数类型时,类型推断失败:

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"

The compiler is able to infer the type 编译器能够推断出类型

My questions are: 我的问题是:

  • Why cannot Scala compiler infer type of the parameter in the third case? 为什么Scala编译器在第三种情况下不能推断出参数的类型?
  • Can I modify the implicit conversion so that the type gets inferred? 我可以修改隐式转换以便推断类型吗?

I'm aware of a related question which touches on this subject but doesn't give an answer to my questions. 我知道一个涉及这个问题相关问题 ,但没有回答我的问题。

The problem doesn't seem to be related to interoperability with Java, btw. 这个问题似乎与Java的互操作性无关,顺便说一句。 If I replace JavaFunction with a custom Scala trait, the behavior remains the same. 如果我用自定义Scala特征替换JavaFunction ,行为将保持不变。

Why cannot Scala compiler infer type of the parameter in the third case? 为什么Scala编译器在第三种情况下不能推断出参数的类型?

To infer type(s) of parameter(s) of a lambda-expression, the expected type must be String => ? 要推断lambda表达式的参数类型期望的类型必须是String => ? (for this case). (对于这种情况)。 In converted3 , the expected type is JavaFunction[String, Int] . converted3 ,期望的类型是JavaFunction[String, Int] This isn't a Scala function, so it won't work. 这不是Scala函数,所以它不起作用。 It will in Scala 2.12, or in 2.11 with -Xexperimental scalac option . 它将在斯卡拉2.12,或2.11与-Xexperimental scalac选项 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. 如果匿名函数的预期类型是scala.Functionn [S1,...,Sn,R]形状,或者可以SAM转换为这样的函数类型,则可以省略参数xi的类型Ti,因为Si以预期的类型定义,并且假设Ti = Si。 Furthermore, the expected type when type checking e is R. 此外,类型检查e时的预期类型是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. 如果函数文字没有预期的类型,则必须显式指定所有形式参数类型Ti,并且未定义e的预期类型。

The "SAM-converted" part is the one activated by -Xexperimental /2.12 and not valid in 2.11 by default. “SAM转换”部分是由-Xexperimental /2.12激活的部分,默认情况下在2.11中无效。

Can I modify the implicit conversion so that the type gets inferred? 我可以修改隐式转换以便推断类型吗?

I don't believe so. 我不相信。 What you can do is to change the place conversion happens: write val unconverted: String => Int = s => s.toInt (or just val unconverted = (s: String) => s.toInt ) and pass it where JavaFunction[String, Int] is expected. 可以做的是更改位置转换发生:写入val unconverted: String => Int = s => s.toInt (或者只是val unconverted = (s: String) => s.toInt val unconverted: String => Int = s => s.toInt val unconverted = (s: String) => s.toInt )并将其传递给JavaFunction[String, Int]是预期的。

When you write val foo: SomeType = bar , the compiler is looking for a way to "prove", that the assignment is valid. 当你写val foo: SomeType = bar ,编译器正在寻找一种“证明”的方法,即赋值是有效的。 This can be proven in one of two ways: either bar has a type, that is a subclass of SomeType (or SomeType itself obviously) or there is an implicit conversion from whatever type bar is to SomeType . 这可以通过以下两种方式之一来证明: bar既有一个类型,也就是SomeType的子类(或者显然是SomeType本身),或者是从任何类型barSomeType的隐式转换。 As yoy can see, in both cases, for the assihnment to work the type of bar has to be known. 正如你可以看到的那样,在两种情况下,为了协助工作,必须知道bar的类型。 But when you write val converted3: JavaFunction[String, Int] = s => s.toInt , the type of right hand side is not defined. 但是当您编写val converted3: JavaFunction[String, Int] = s => s.toInt ,未定义右侧的类型。 The compiler knows, that it is some function, returning an Int, but without the type of argument, it is not enough. 编译器知道它是一些函数,返回一个Int,但没有参数类型,这还不够。

Anoher way to say it is that the compiler will not check every implicit conversion in scope, returning something compatible with the LHS, in order to use the conversion, it needs to know the input type. 另一种说法是编译器不会检查范围内的每个隐式转换,返回与LHS兼容的东西,为了使用转换,它需要知道输入类型。

There is no way around it AFAIK, you have to define the type of the rhs one way or another on order to be able to use the implicit conversion. AFAIK无法绕过它,你必须以某种方式定义rhs的类型才能使用隐式转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM