Как вы можете хранить массив протоколов со связанными типами в Swift, не используя Any? - PullRequest
0 голосов
/ 24 июня 2019

Я пытаюсь сделать что-то вроде этого:

protocol StateType { }

struct DogState: StateType { }

struct CatState: StateType { }

protocol Action {
    associatedType ST
    func process() -> ST
}

struct DogAction {
    func process() -> DogState { return DogState() }
}

struct CatAction {
    func process() -> CatState { return CatState() }
}

let actions = [DogAction(), CatAction()]

actions.forEach {
    $0.process()
}

Я пытался дурачиться с стиранием типов, но не могу решить проблему невозможности создания гетерогенных массивов.

struct AnyActionProtocol<A: Action, ST: StateType>: Action  where A.StateType == ST {
    let action: A

    init(_ action: A) {
        self.action = action
    }

    func process() -> ST {
        return action.process()
    }
}

let dap = AnyActionProtocol<DogAction, DogState>(DogAction())
let cap = AnyActionProtocol<CatAction, CatState>(CatAction())

Когда я пытаюсь это сделать, я получаю сообщение об ошибке: Литерал гетерогенной коллекции может быть выведен только для [Любой], чего я стараюсь избегать.

Любая помощь будетоценили!

1 Ответ

0 голосов
/ 24 июня 2019

PAT обычно сложны и не требуют более простого решения. Я бы посоветовал вам придумать более простой дизайн для вашей проблемы. Проблема с вашим методом на самом деле заключается в том, что у вас есть PAT и вложенные протоколы, и вы пытаетесь заставить их работать вместе.

Даже если вы наберете erase Action для какого-либо типа, например AnyAction, эти два разных типа DogAction и CatAction снова создадут разные типы, и вы не сможете смешивать их внутри массива. Что вы можете сделать, это иметь два типа стираний, один для Action, а другой для StateType. Когда вы оборачиваете CatAction или DogAction внутри AnyAction, они оба затем переносятся в состоянии стирания типа до AnyState.

Вот один пример, к которому вы могли бы приблизиться, стирая оба протокола,

protocol StateType { }

struct DogState: StateType { }

struct CatState: StateType { }

protocol Action {
    associatedtype ST: StateType
    func process() -> ST
}

struct DogAction: Action {
    func process() -> DogState { return DogState() }
}

struct CatAction: Action {
    func process() -> CatState { return CatState() }
}

struct AnyState: StateType {
    let state: StateType

    init(_ state: StateType) {
        self.state = state
    }
}


struct AnyAction: Action {
    typealias ST = AnyState

    let processor: () -> AnyState

    init<T: Action>(_ a: T)  {
        self.processor = {
            return AnyState(a.process())
        }
    }

    func process() -> AnyState {
        return processor()
    }
}


let cat = AnyAction(CatAction())
let dog = AnyAction(DogAction())

let actions = [cat, dog]

actions.forEach { action in
    action.process()
}

Я все еще думаю, что вам следует переосмыслить свое решение, это может усложниться по мере увеличения количества типов.

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