Объявление универсального свойства протокола

#swift

#swift

Вопрос:

Предположим, у меня есть протокол с соответствующим типом T

 protocol Helper{
    associatedtype T
    func help(_ item: T)
}
  

в классе я хочу объявить свойство

 class Manager<T>{
    let item: T?
    let helper: Helper<T>
//Error: Cannot specialize non-generic type 'Helper'

    let anotherHelper: Helper 
//Error: Protocol 'Helper' can only be used as a generic constraint because it has Self or associated type requirements
}
  

Как мне объявить и использовать вспомогательное свойство таким образом, чтобы оно применяло тип класса, соответствующий вспомогательному протоколу?

Я уверен, что многие люди, имеющие опыт работы с Java / C # или другими подобными языками, застревают при попытке выполнить аналогичные действия

Ответ №1:

В этом конкретном случае вы могли бы сделать T in Manager<T> вместо Helper :

 class Manager<T> where T : Helper {
    let item: T.T?
    let helper: T

    init(helper: T) {
        self.helper = helper
        item = nil
    }
}
  

И если вы хотите Helper<Int> , вы делаете:

 class IntHelper : Helper {
    typealias T = Int

     // ... 
}
  

А затем используйте Manager<IntHelper> .

Комментарии:

1. Даже если это, похоже, решает этот конкретный случай, это не отвечает на вопрос. Обычно T будет моделью, а помощники — это потребители, которые выполняют действие над моделью / с ней. Как бы выглядел код, который выполняет именно это?

Ответ №2:

Возможно, вам понадобится средство удаления типов:

 struct AnyHelper<T>: Helper {
    private let helpFunc: (T) -> Void

    init<H>(_ helper: H) where Helper.T == T {
        helpFunc = helper.help
    }

    func help(_ item: T)
        helpFunc(item)
    }
}
  

а затем используйте средство удаления типов в вашем классе:

 class Manager<T>{
    let item: T?
    let helper: AnyHelper<T>

    init<H>(item: T, helper: H) where H.T == T {
        self.item = item
        self.helper = AnyHelper(helper)
    }
}