Подтвердить что ты не робот

Почему этот протокол "может использоваться только как общее ограничение"?

Я пытаюсь сделать следующее в Swift:

protocol ProtocolWithAlias {
    typealias T
}

protocol AnotherProtocol {
    func someFunc() -> ProtocolWithAlias
}

Но я получаю ошибку: Protocol 'ProtocolWithAlias' can only be used as a generic constraint because it has Self or associated type requirements.

Можно ли сделать что-то подобное? Сообщение об ошибке (или, по крайней мере, часть "only be used as a generic constraint" ), кажется, не имеет большого смысла для меня.

Я использую последнюю версию Xcode 6 beta 3.

Спасибо!

4b9b3361

Ответ 1

Попробуйте следующее:

func someFunc<T:ProtocolWithAlias>() -> T

Ответ 2

Это можно реализовать, инвертируя элемент управления: вместо того, чтобы возвращать значение из someFunc, мы передаем потребителю, который может принимать любые типы, реализующие ProtocolWithAlias, и что-то делать с ним.

protocol ProtocolWithAlias {
    typealias T
}

protocol ProtocolConsumer {
    func consume<T: ProtocolWithAlias>(value: T)
}

protocol AnotherProtocol {
    func someFunc(consumer: ProtocolConsumer)
}

Этот трюк известен как преобразование функции в стиль продолжения передачи (CPS). К сожалению, я не смог найти способ реализовать это без CPSing. Тип системы, который мы ищем, - это экзистенциальные типы (и этот поток имеет приятное объяснение), но я думаю, что Swift их не поддерживает (пока).


Почему другой ответ не правильный? Что говорит эта подпись:

func someFunc<T:ProtocolWithAlias>() -> T

заключается в том, что эта функция может возвращать значение типа T для любого типа, реализующего ProtocolWithAlias, который выбирает вызывающий, но мы хотели, чтобы он был выбран вызываемым.

Невозможно даже написать разумную реализацию этой функции. Давайте сделаем вид, что у меня есть реализация someFunc: я мог бы создать новый класс, реализующий ProtocolWithAlias, и попросить someFunc каким-то образом создать экземпляр этого класса:

class Uninhabited: ProtocolWithAlias {
    typealias T = Int
    init(nope: Uninhabited) {}
}

...

let impossible: Uninhabited = someFunc<Uninhabited>()