2016-04-24 15 views
2

Ich möchte eine implizite Konvertierung von einer Scala-Funktion (möglicherweise anonym) zu java.util.function.Function erstellen. Hier ist, was ich habe:Implizite Konvertierung von Scala-Funktion in Java-Funktion

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

Es funktioniert gut, außer dass die Typinferenz versagt, wenn die Funktion umgewandelt werden nicht Parametertyp explizit angeben:

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" 

Der Compiler ist in der Lage, den Typ zu schließen,

Meine Fragen sind:

  • Warum kann der Scala-Compiler im dritten Fall nicht den Typ des Parameters ableiten?
  • Kann ich die implizite Konvertierung so ändern, dass der Typ abgeleitet wird?

Ich kenne eine related question, die auf dieses Thema berührt, aber keine Antwort auf meine Fragen gibt.

Das Problem scheint nicht im Zusammenhang mit der Interoperabilität mit Java, BTW. Wenn ich JavaFunction durch eine benutzerdefinierte Scala-Eigenschaft ersetze, bleibt das Verhalten gleich.

+0

A [verwandten Artikel] (http://www.tikalk.com/incubator/simulating-sam-closures-scala/) Ich fand. Es liefert keine Antwort, sondern berührt das verwandte Thema der impliziten Konvertierung der Scala-Funktion. – Mifeet

Antwort

3

Warum kann der Scala-Compiler den Typ des Parameters im dritten Fall nicht ableiten?

Typen (en) der (die) Parameter eines Lambda-Ausdruck abzuleiten, der erwartete Typ muss String => ? (für diesen Fall) sein. In converted3 ist der erwartete Typ JavaFunction[String, Int]. Dies ist keine Scala-Funktion, also wird es nicht funktionieren. Es wird in Scala 2.12 oder in 2.11 mit -Xexperimental scalac option. Dies ist nach the specification:

Wenn die erwarteten Typ der anonymen Funktion der Form ist scala.Functionn [S1, ..., Sn, R], oder kann mit einem solchen Funktionstyp SAM-umgewandelt werden, der Typ Ti eines Parameters xi kann so weit weggelassen werden, wie Si in den erwarteten Typ definiert ist, und Ti = Si angenommen wird. Darüber hinaus ist der erwartete Typ, wenn Typ Überprüfung e R. ist

Wenn es kein erwarteter Typ für die Funktionsliteral ist, wird alle formalen Parameter Typen Ti explizit angegeben werden muß, und die erwartete Art von e ist nicht definiert.

Die "SAM-gewandelten" Teil der von -Xexperimental /2.12 und nicht gültig in 2.11 standardmäßig aktiviert ist.

Kann ich die implizite Konvertierung so ändern, dass der Typ abgeleitet wird?

Ich glaube nicht. Was Sie können tun, ist die Änderung der Ort Umwandlung geschieht: Schreiben Sie val unconverted: String => Int = s => s.toInt (oder nur val unconverted = (s: String) => s.toInt) und übergeben Sie es, wo JavaFunction[String, Int] erwartet wird.

+0

Danke für Ihre Antwort. Könnten Sie bitte einen Hinweis darauf geben, warum der erwartete Typ "String =>?" Sein muss? – Mifeet

+0

@Mifeet Bearbeiten. –

+0

Danke, das ist, was ich gesucht habe. – Mifeet

1

Wenn Sie val foo: SomeType = bar schreiben, sucht der Compiler nach einer Möglichkeit zu "beweisen", dass die Zuweisung gültig ist. Dies kann auf eine von zwei Arten nachgewiesen werden: entweder bar hat einen Typ, das ist eine Unterklasse von SomeType (oder SomeType selbst offensichtlich) oder es gibt eine implizite Konvertierung von welchem ​​Typ bar ist zu SomeType. Wie man in beiden Fällen sehen kann, muss der Typ bar bekannt sein. Aber wenn Sie val converted3: JavaFunction[String, Int] = s => s.toInt schreiben, ist der Typ der rechten Seite nicht definiert. Der Compiler weiß, dass es eine Funktion ist, die einen Int zurückgibt, aber ohne die Art des Arguments ist es nicht genug.

Eine andere Art zu sagen ist, dass der Compiler nicht jede implizite Konvertierung im Geltungsbereich überprüft und etwas mit der LHS kompatibles zurückgibt, um die Konvertierung zu verwenden, muss es den Eingabetyp kennen.

Es gibt keinen Weg um AFAIK, Sie müssen den Typ der rhs auf die eine oder andere Weise definieren, um die implizite Konvertierung verwenden zu können.

+0

Vielen Dank für Ihre Antwort. Ich stimme der Aussage, dass die Art der "Bar" bekannt sein muss, nicht völlig zu. Z.B. In 'val f: Funktion1 [String, Int] = s => s.toInt' wird der Typ von RHS abgeleitet, ohne explizit anzugeben, dass 's' ein 'String' ist. – Mifeet

+0

@Mifeet in diesem Fall ist der Typ von rhs bekannt als 'Function1 [String, Int]', da keine implizite Konvertierung involviert ist. Also, was ich gesagt habe, gilt: Die Art der rhs muss bekannt sein. – Dima

+0

Nun, wenn du meinst "erwartete Art der anonymen Funktion" ist bekannt, dann stimme ich zu. Der Typ von RHS muss jedoch nicht "Function1 [String, Int]" sein, sondern kann beispielsweise "Function1 [Object, Int]" sein. Ich weiß, das sind feine Unterschiede, Entschuldigung für Nörgelei :). – Mifeet

Verwandte Themen