Безопасность типов в Котлине не работает должным образом - PullRequest
0 голосов
/ 07 июня 2018

У меня есть такой код:

enum class Player { PLAYER, COMPUTER }

interface BoardCell {
    val x: Int
    val y: Int
    var player: Player?
}

data class Cell(val x: Int, val y: Int, var player: Player?, var value: Int)
data class BoardCellClass(override val x: Int, override val y: Int, override var player: Player?) : BoardCell
data class Request(val board: MutableList<MutableList<BoardCellClass>>? = null, val occupied: MutableList<BoardCellClass>? = null)

class AI(board: MutableList<MutableList<BoardCell>>, private var occupied: MutableList<BoardCell>) {
    private var board: MutableList<MutableList<Cell>> = board.map { it.map { Cell(it.x, it.y, it.player, 0) } .toMutableList() } .toMutableList()
}

// in main

val request = call.receive<Request>()

if (request.board == null || request.occupied == null) {
    // respond with 403
} else {
    val ai = AI(request.board, request.occupied) // Kotlin: Type mismatch: inferred type is MutableList<MutableList<BoardCellClass>>? but MutableList<MutableList<BoardCell>> was expected
                                                 // Kotlin: Type mismatch: inferred type is MutableList<BoardCellClass>? but MutableList<BoardCell> was expected
}

Но это ошибки с тем, что в комментарии внизу.Что я делаю неправильно?Ясно, что есть оператор if, который улавливает ничтожность, поэтому он должен быть не типа MutableList<MutableList<BoardCellClass>>?, а MutableList<MutableList<BoardCellClass>>, нет?Кроме того, MutableList<MutableList<BoardCellClass>> совместим с MutableList<MutableList<BoardCell>>, потому что он реализует этот интерфейс, верно?

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

MutableList> совместим с MutableList>, потому что он реализует этот интерфейс, верно?

Нет.В вашем случае вы можете использовать out ключевое слово

class AI(board: MutableList<MutableList<BoardCell>>, private var occupied: MutableList<out BoardCell>) {
    private var board: MutableList<MutableList<Cell>> = board.map { it.map { Cell(it.x, it.y, it.player, 0) } .toMutableList() } .toMutableList()
}

Очевидно, что есть оператор if, который ловит нуль, поэтому он не должен иметь тип

Вы можете написать этот код в том случае, если (не иначе) часть, чтобы компилятор понял вас правильно

if (request.board != null && request.occupied != null){
     val ai = AI(request.board, request.occupied)
} else {
    // respond with 403
}
0 голосов
/ 07 июня 2018

Кроме того, MutableList<MutableList<BoardCellClass>> совместим с MutableList<MutableList<BoardCell>>, потому что он реализует этот интерфейс, верно?

Нет, это не так.Это проблема дисперсия .Поиск «дисперсии Котлина» даст вам много объяснений, но самый простой способ понять, почему MutableList<BoardCellClass> не является подтипом MutableList<BoardCell>, это

val list: MutableList<BoardCellClass> = ...
val list1: MutableList<BoardCell> = list // illegal in actual Kotlin!
list1.add(object : BoardCell { ... }) // would add a BoardCell to a MutableList<BoardCellClass>

Тогда ту же логику можно поднять доуровень, чтобы увидеть, что MutableList<MutableList<BoardCellClass>> не подтип MutableList<MutableList<BoardCell>>.

Понятно, что есть оператор if, который улавливает ничтожность, поэтому он должен иметь тип MutableList<MutableList<BoardCellClass>>?, но MutableList<MutableList<BoardCellClass>>, нет?

Этоне совсем то, как работают умные броски Kotlin (хотя в большинстве случаев разница не актуальна).Он по-прежнему имеет тип MutableList<MutableList<BoardCellClass>>?, но если он используется там, где требуется тип MutableList<MutableList<BoardCellClass>>, он автоматически разыгрывается.Здесь вместо этого требуется тип MutableList<MutableList<BoardCell>>, и поэтому приведение не вставляется, и в сообщении об ошибке отображается тип NULL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...