2016-04-24 73 views
2

我想創建一個從Scala函數(可能是匿名)到java.util.function.Function的隱式轉換。以下是我有:從Scala函數到Java函數的隱式轉換

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,行爲仍然是一樣的。

+0

A [相關文章](http://www.tikalk.com/incubator/simulating-sam-closures-scala/)我找到了。它沒有提供答案,但觸及了Scala函數隱式轉換的相關主題。 – Mifeet

回答

3

爲什麼Scala編譯器不能推斷第三種情況下的參數類型?

來推斷λ-表達的參數(一個或多個)的類型(一個或多個)時,預期類型必須String => ?(對於這種情況下)。在converted3中,預期類型爲JavaFunction[String, Int]。這不是一個Scala函數,所以它不起作用。它的將在斯卡拉2.12中爲,或者在與-Xexperimental scalac option的2.11中。這是根據本the specification

如果預期的類型匿名函數的是形狀scala.Functionn的[S1,...,Sn的,R],或者可以被SAM-轉化爲這樣的函數式中,參數 XI 的類型 鈦 可以省略,只要 硅 在預期的類型被定義,並且 鈦 = 硅 假設。此外,當類型檢查 Ë 預期的類型是 R.

如果不存在預期類型的​​函數文本,所有的正式參數類型的Ti必須明確指定和預期型電子商務是不確定的。

的「SAM-轉化」部分是一個由-Xexperimental /2.12和無效激活2.11默認。

我可以修改隱式轉換,以便推斷出類型嗎?

我不這麼認爲。你可以做的是改變地點轉換髮生:寫val unconverted: String => Int = s => s.toInt(或只是val unconverted = (s: String) => s.toInt),並通過它JavaFunction[String, Int]預計。

+0

感謝您的回覆。你能否提供一些參考,爲什麼期望的類型必須是'String =>?'? – Mifeet

+0

@Mifeet查看編輯。 –

+0

謝謝,那就是我一直在尋找的東西。 – Mifeet

1

當您編寫val foo: SomeType = bar時,編譯器正在尋找一種「證明」的方式,即賦值是有效的。這可以通過以下兩種方式之一來證明:bar有一個類型,即SomeType(或明顯是SomeType本身)的子類,或者存在從任何類型barSomeType的隱式轉換。 同樣可以看到,在這兩種情況下,工作單位都需要知道bar的類型。但是當你寫val converted3: JavaFunction[String, Int] = s => s.toInt時,右側的類型沒有定義。編譯器知道它是一個函數,返回一個Int,但沒有參數類型,這是不夠的。

另一種說法是,編譯器不會檢查範圍內的每個隱式轉換,返回與LHS兼容的東西,爲了使用轉換,它需要知道輸入類型。

有沒有辦法繞過它AFAIK,你必須定義rhs的類型,以便能夠使用隱式轉換。

+0

謝謝你的回答。我不完全同意「bar」的類型必須知道的說法。例如。在'val f:Function1 [String,Int] = s => s.toInt'中,RHS的類型被推斷出來,但沒有明確指出's'是一個'String'。 – Mifeet

+0

@Mifeet在這種情況下,rhs的類型被稱爲'Function1 [String,Int]',因爲不存在隱式轉換。所以,我所說的是:rhs的類型必須是已知的。 – Dima

+0

那麼,如果你的意思是「預期類型的​​匿名函數」是已知的,那麼我同意。但是RHS的類型不需要是'Function1 [String,Int]',它可以是,例如'Function1 [Object,Int]'。我知道這些是微妙的差異,抱歉嘮叨:)。 – Mifeet