def moves (player : Player)
означает, что moves
принимает игрока за , это Game
.
Game#Player
- это тип для игрока любой Game
.Итак, moves (player)
является несовпадением типов.
Вот простой пример, который показывает, почему должно быть несовпадением.Предположим, что это не так, и посмотрим, что будет дальше:
class Game2 extends DummyGame {
override type Player = Boolean
override type Move = Boolean
override def moves(player : Boolean) = new Iterator[Boolean] {...}
}
val game2: DummyGame = new Game2
// game2.Player is Boolean
val dummyGameAi = new DummyAi[DummyGame](game2)
// DummyGame#Player == Unit, so the type of genMove for Ai[DummyGame] is
// def genMove (player : Unit) : Unit
dummyGameAi.genMove(())
// this calls game2.moves(()), which doesn't typecheck
Чтобы заставить это работать, мы можем изменить тип genMove
.Если мы передадим игру в качестве аргумента (и в любом случае это имеет смысл), мы можем использовать зависимые от пути типы:
abstract class Ai[Game <: AGame] {
def genMove (game : Game)(player : game.Player) : game.Move
// now game.moves (player) typechecks
}