#swift #generics
#swift #общие
Вопрос:
Учитывая протокол без каких-либо проблем вообще:
protocol NonFunkyProtocol {}
И протокол, в котором происходят серьезные сбои:
protocol FunkyProtocol {
func funky<T: NonFunkyProtocol>(_ closure: (T) -> Void)
}
Затем, учитывая эту структуру:
struct WeeStruct: FunkyProtocol {
let weeProp: NonFunkyProtocol
func funky<T>(_ closure: (T) -> Void) where T: NonFunkyProtocol {
closure(weeProp)
}
}
Я ожидал бы, что это будет скомпилировано, поскольку тип параметра, ожидаемый в closure
, равен T, где T соответствует NonFunkyProtocol и weeProp
имеет тип NonFunkyProtocol.
Вместо этого я вижу эту ошибку:
У меня, скорее всего, где-то в моих знаниях общих терминов есть пробел, где я ошибаюсь?
Ответ №1:
Проблема в том, что T
в данном случае это «некоторый тип, который соответствует NonFunkyProtocol
«. weeProp
также «что-то, что соответствует NonFunkyProtocol
«, но ничто не говорит о том, что weeProp
имеет тип T
.
Рассмотрим следующий случай:
extension Int: NonFunkyProtocol {}
extension String: NonFunkyProtocol {}
Оба Int и String соответствуют.
Теперь я создаю WeeStruct со строкой:
let wee = WeeStruct(weeProp: "")
И я вызываю funky
функцию, для которой требуется значение Int (поскольку Int соответствует типу, это может быть T
):
wee.funky { (int: Int) -> Void in print(int 1) }
Таким образом, это передалось бы ""
к закрытию. Как это может работать?
Таким образом, вам либо нужно запросить дескриптор закрытия any NonFunkyProtocol
(я сильно подозреваю, что это то, что вы имеете в виду):
func funky(_ closure: (NonFunkyProtocol) -> Void)
Или вам нужно закрепить weeProp
до T
, создав T
associatedtype:
protocol FunkyProtocol {
associatedtype T: NonFunkyProtocol
func funky(_ closure: (T) -> Void)
}
struct WeeStruct<T:NonFunkyProtocol>: FunkyProtocol {
let weeProp: T
func funky(_ closure: (T) -> Void) {
closure(weeProp)
}
}
Однако я был бы очень осторожен, прежде чем добавлять associatedtype . Это полностью меняет природу FunkyProtocol.
Если FunkyProtocol действительно является только этим требованием, вам также следует спросить, что он решает, а не просто функцию. Зачем передавать WeeStruct
весь свой протокольный багаж, когда вы могли бы просто использовать wee.funky
функцию напрямую? Есть ли расширение протокола в FunkyProtocol? Если вы не можете написать универсальные алгоритмы для FunkyProtocol, вероятно, это не должен быть протокол.
Комментарии:
1. Момент лампочки! Большое спасибо, в этом конкретном примере вы правы, это не должен быть протокол, но это был просто очень дистиллированный пример, чтобы попытаться обдумать проблему, с которой я столкнулся в одном из моих проектов.