我在 Kotlin 代碼中使用的 Scala 庫提供了一個函式,該函式需要 ascala.collection.immutable.Map<String!, String!>!作為引數。
舉一個最小的例子,讓我們呼叫這個函式f。我想將給定 Kotlin 的值映射到它,但我正在努力進行轉換:
fun f(x: scala.collection.immutable.Map<String, String>) {}
fun main() {
val m = mapOf("foo" to "bar")
val m2 = scala.jdk.CollectionConverters.MapHasAsScala(m).asScala()
f(m2)
}
錯誤:
Type mismatch.
Required:
scala.collection.immutable.Map<String, String>
Found:
scala.collection.mutable.Map<String!, String!>!
我明白,我應該使用.toMap,但我不允許在不提供ev引數的情況下呼叫此函式:
val m2 = scala.jdk.CollectionConverters.MapHasAsScala(m).asScala().toMap<String, String>()
錯誤:
No value passed for parameter 'ev'
我錯過了什么?
uj5u.com熱心網友回復:
找到了一個解決方案scala.collection.immutable.Map.from,并將其放入擴展函式中。:)
fun <A, B> Map<A, B>.toImmutableScalaMap(): scala.collection.immutable.Map<A, B> =
scala.collection.immutable.Map.from(scala.jdk.CollectionConverters.MapHasAsScala(this).asScala())
fun main() {
val m = mapOf("foo" to "bar")
f(m.toImmutableScalaMap())
}
uj5u.com熱心網友回復:
首先,該ev引數是一個隱含的證據,它表明可迭代物件中的泛型型別“即A”是 的子型別(String, String)。這可以由 scala 中的編譯器計算出來,而無需為其傳遞引數(它是隱式的)。所以在 Scala 這有效:
val myMap = ... //of type scala.collection.mutable.Map[String, String]
val immutableMap = myMap.toMap // scala.collection.immutable.Map[String, String]
但是在 Kotlin 或 Java 中使用它需要傳遞一個型別的實體<:<[(String, String), (String, String)](意味著 2 個字串的元組,是 2 個字串的元組的子型別,這實際上是正確的)。我不認為你可以這樣做,你也不能這樣做,因為非法繼承。我有 2 條建議。
第一:創建一個 Scala 物件,它可以很容易地為你做到這一點
object MapConvertor {
def mutableToImmutable[K, V](mutableMap: scala.collection.mutable.Map[K, V]) = mutableMap.toMap
}
只需在您的 Kotlin 檔案中呼叫它(如MapConvertor.mutableToImmutable(...)),它們是二進制兼容的,不會有任何問題。
Scala 中的第二個 Map,也混合了 IterableOnce 特征(實作了 IterableOnce 介面,這更像 Java :D)。所以你可以將它轉換為超型別。Map 還有一個靜態方法,可以從 IterableOnce 創建地圖。所以:
scala.collection.IterableOnce<scala.Tuple2<String, String>> immutableMapIterable;
immutableMapIterable = (scala.collection.IterableOnce<scala.Tuple2<String, String>>) Test.m();
return scala.collection.immutable.Map.from(immutableMapIterable);
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/474431.html
