在處理代碼出現問題時,我發現自己定義了一個函式來轉置整數矩陣:
fun transpose(xs: Array<Array<Int>>): Array<Array<Int>> {
val cols = xs[0].size // 3
val rows = xs.size // 2
var ys = Array(cols) { Array(rows) { 0 } }
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
事實證明,在下面的謎題中,我還需要轉置一個矩陣,但它不是Ints的矩陣,所以我嘗試進行概括。在 Haskell 中,我會有一些型別的東西
transpose :: [[a]] -> [[a]]
并在 Kotlin 中復制它,我嘗試了以下操作:
fun transpose(xs: Array<Array<Any>>): Array<Array<Any>> {
val cols = xs[0].size
val rows = xs.size
var ys = Array(cols) { Array(rows) { Any() } } // maybe this is the problem?
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
這似乎沒問題,但事實并非如此。事實上,當我嘗試在原始整數矩陣上呼叫它時,我得到了Type mismatch: inferred type is Array<Array<Int>> but Array<Array<Any>> was expected. 問題是,我真的不明白這個錯誤資訊:我認為Any是其他任何東西的超型別?
谷歌搜索我以為我明白我應該使用某種型別約束語法(抱歉,不確定它在 Kotlin 中的呼叫方式),從而將型別更改為fun <T: Any> transpose(xs: Array<Array<T>>): Array<Array<T>>,但是在回傳行我得到Type mismatch: inferred type is Array<Array<Any>> but Array<Array<T>> was expected
所以我的問題是,如何撰寫transpose適用于任何二維陣列的矩陣?
uj5u.com熱心網友回復:
正如您自己指出的那樣,該行Array(cols) { Array(rows) { Any() } }創建了一個Array<Array<Any>>,因此如果您在通用函式中使用它,您將無法在Array<Array<T>>預期時回傳它。
相反,您應該使用這個 lambda 來直接為正確的索引提供正確的值(而不是初始化為任意值并替換所有值):
inline fun <reified T> transpose(xs: Array<Array<T>>): Array<Array<T>> {
val cols = xs[0].size
val rows = xs.size
return Array(cols) { j ->
Array(rows) { i ->
xs[i][j]
}
}
}
我不太明白這個錯誤資訊:我認為 Any 是其他任何東西的超型別?
這是因為Kotlin 中的陣列的元素型別是不變的。如果您不了解泛型變化,那么它是關于描述泛型型別的層次結構與其型別引數的層次結構的比較。
例如,假設您有一個型別Foo<T>。現在,Int是 的子型別這一事實Any并不一定意味著它Foo<Int>是 的子型別Foo<Any>。您可以查找行話,但基本上您在這里有 3 種可能性:
- 如果是(型別“以相同方式變化” )的子型別,我們說它的型別引數
Foo是協變的TFoo<Int>Foo<Any>FooT - 如果是(與 相比,型別“以相反的方式變化” )的超型別,我們說它的型別引數
Foo是逆變的TFoo<Int>Foo<Any>FooT - 如果以上都不能說,我們就說它的型別引數
Foo是不變的T
Kotlin 中的陣列是不變的。List然而,Kotlin 的 read-only在其元素型別上是協變的。這就是為什么可以將 a 分配給Kotlin 中List<Int>的型別變數的原因List<Any>。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/375638.html
下一篇:關于模塊的全面實作的規則是什么?
