Есть ли способ установить тип данных протокола в функции указателя? - PullRequest
0 голосов
/ 09 апреля 2019

Есть ли способ установить тип данных протокола в указателе функции в swift?

Вот мой протокол ICRUDOperation

public protocol ICRUDOperation {
    associatedtype T
    func insert(data:T)
    func update(data:T)
    func get(data:T) -> [T]
    func getList(data: BaseModel) -> [T]
    func getPage(data: BaseModel) -> [T]
    func delete(data: T)
}

, который я пытаюсь использовать в:

func delegate1<W>(sqlite: W, service: W, data: W.T) where W: ICRUDOperation {
    sqlite.insert(data: data)
}
var decision = [String : [String:((ICRUDOperation, ICRUDOperation, T) ->())?]]()

func fillDecision() {
    decision["Person"]?["1"] = Delegate1
}

Я получаю эту ошибку в решении

Protocol 'ICRUDOperation' can only be used as a generic constraint because it has Self or associated type requirements

Ошибка для fillDecision():

Cannot assign value of type '(_, _, _.T) -> ()' to type '((ICRUDOperation, ICRUDOperation, _) -> ())??'

Ответы [ 2 ]

1 голос
/ 09 апреля 2019

После того, как вы добавили связанный тип, больше не существует такой вещи, как «ICRUDOperation».PAT (протокол со связанным типом) не имеет экзистенциальной формы;он существует для присоединения методов к другим типам или для ограничения того, какие конкретные типы могут быть переданы универсальной функции.Вы не можете хранить PAT в переменной, словаре или где-либо еще.Протокол (и вдвойне PAT) не является абстрактным классом.

Самая важная вещь для понимания - это то, что связанные типы выбираются реализацией , а не вызывающей стороной.Так что в вашем примере T будет выбрано реализацией ICRUDOperation (так же, как Array выбирает свой Collection.Index как Int; вы не можете выбрать это).Обобщения позволяют абоненту выбирать тип, который больше похож на то, что вы пытаетесь достичь.

Способ решения этой проблемы зависит от вашего варианта использования, который трудно понять из вашегопример.Какова цель decision?

Было бы полезно, если бы вы продемонстрировали, как вы ожидаете, как будут выглядеть две или три разные реализации ICRUDOperation.Я не уверен, что вы подразумеваете под "реализацией операции".

0 голосов
/ 09 апреля 2019

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

struct Item {
    var id: Int
    var name: String
}

Тогда нам нужен обработчик, который может выполнять операции с БД.

struct ItemDbHandler: ICRUDOperation {
    typealias T = Item

    func insert(data: Item) {
        print("\(#function) \(item)")
    }

    func update(data: Item) {
        print("\(#function) \(item)")
    }

    func get(data: Item) -> [Item] { //shouldn't this return 1 element
        print("\(#function) \(item)")
        return []
    }
    // and so on...
}

И с некоторой функцией делегата

func delegateUpdate<W>(sqlite: W, service: W, data: W.T) where W: ICRUDOperation {
    sqlite.update(data: data)
}

мы можем работать с обработчиком напрямую или через функцию

var item = Item(id: 1, name: "ABC")
var handler = ItemDbHandler()
handler.insert(data: item)
item.name = "abc"

delegateUpdate(sqlite: handler, service: handler, data: item)

Запуск этого на детской площадке дает

вставить (данные :) Элемент (id: 1, имя: "ABC")
обновление (данные :) Элемент (id: 1, имя: "abc")

Я не понимаю, что вы хотите сделать fillDecision, поэтому я пропустил это сейчас.

...