Использование ассоциированного типа в протоколе делегата для универсального типа

У меня есть Game класс. Я сделал его универсальным, потому что мне нужно было поддерживать различные типы плат. Теперь я просто хочу добавить классический делегат в стиле iOS с методом, который будет принимать игру и новое значение очков в качестве параметров. Как добиться этого способом Swift associatedtype? Я действительно смущен тем, что не могу реализовать такую ​​простую логику.

protocol GamePointsDelegate {
    associatedtype B: Board
    func game(_ game: Game<B>, didSetPoints points: Int)
}

class Game<B: Board> {
    let board: Board

    var points = 0 {
        // Compiler Error
        // Member 'game' cannot be used on value of protocol type 'GamePointsDelegate'; use a generic constraint instead
        didSet { pointsDelegate?.game(self, didSetPoints: points) }
    }

    // Compiler Error
    // Protocol 'GamePointsDelegate' can only be used as a generic constraint because it has Self or associated type requirements
    var pointsDelegate: GamePointsDelegate?
}

person kelin    schedule 02.12.2017    source источник
comment
Возможно ли удалить связанный тип и просто использовать общую функцию game?   -  person Qbyte    schedule 03.12.2017
comment
У вас не может быть var pointsDelegate типа GamePointsDelegate, потому что GamePointsDelegate не является типом. Это как шаблон для типа, который создает новый тип для каждого возможного значения B.   -  person Alexander    schedule 03.12.2017
comment
@Александр, я понял. Но у меня уже есть B в Game, и я хочу как-то это использовать.   -  person kelin    schedule 03.12.2017
comment
@kelin Если вы должны использовать связанный тип в GamePointsDelegate, то Game нужен новый общий параметр, назовите его Delegate, типа GamePointsDelegate, где Self.Delegate.B == Self.B.   -  person Alexander    schedule 03.12.2017
comment
@Александр, спасибо за объяснение. Я бы предпочел универсальную функцию, потому что она намного проще.   -  person kelin    schedule 03.12.2017
comment
@kelin Да, это предпочтительный выбор. Я просто указываю на то, что необходимо для того, чтобы этот подход ассоциированного типа работал.   -  person Alexander    schedule 03.12.2017


Ответы (1)


Вы можете удалить связанное требование типа из своего протокола и вместо этого использовать общую функцию game:

protocol GamePointsDelegate {
    func game<B>(_ game: Game<B>, didSetPoints points: Int)
}

Таким образом, вы можете использовать код вашего класса Game как есть, но недостатком является то, что класс, соответствующий протоколу, должен обрабатывать все Board.

person Qbyte    schedule 02.12.2017
comment
Это дает мне предупреждение: избыточное ограничение соответствия «B»: «Board». Но если я удалю Board из общей декларации, все скомпилируется. Спасибо! - person kelin; 03.12.2017