Расширения протокола в Structs вызывают ошибку компиляции "Я", ограниченную не-протокольным типом
Я пытаюсь применить ограниченное расширение протокола к структуре (Swift 2.0) и получить следующую ошибку компилятора:
тип "Я", ограниченный не-протокольным типом "Foo"
struct Foo: MyProtocol {
let myVar: String
init(myVar: String) {
self.myVar = myVar
}
}
protocol MyProtocol {
func bar()
}
extension MyProtocol where Self: Foo {
func bar() {
print(myVar)
}
}
let foo = Foo(myVar: "Hello, Protocol")
foo.bar()
Я могу исправить эту ошибку, изменив struct Foo
на class Foo
, но я не понимаю, почему это работает. Почему я не могу сделать where Self:
ограниченный протокол struct?
Ответы
Ответ 1
Это ожидаемое поведение с учетом struct
не предназначено для наследования, которое обозначает обозначение :
.
Правильный способ достижения того, что вы описали, будет выглядеть как знак равенства:
extension MyProtocol where Self == Foo {
func bar() {
print(myVar)
}
}
Но это не скомпилируется по какой-то глупой причине вроде:
Требование к одному типу делает общий параметр Self
не общим
Для чего это стоит, вы можете добиться того же результата со следующим:
protocol FooProtocol {
var myVar: String { get }
}
struct Foo: FooProtocol, MyProtocol {
let myVar: String
}
protocol MyProtocol {}
extension MyProtocol where Self: FooProtocol {
func bar() {
print(myVar)
}
}
где FooProtocol
является поддельным protocol
, который должен расширять только Foo
.
Многие сторонние библиотеки, которые пытаются использовать типы extend
стандартной библиотеки struct
(например, необязательно), используют обходное решение, подобное приведенному выше.
Ответ 2
Я тоже столкнулся с этой проблемой. Хотя мне также хотелось бы лучше понять, почему это так, ссылка на язык Swift (об этом ничего не говорится об этом) содержит раздел "Общие параметры":
Где Классы
Вы можете указать дополнительные требования к параметрам типа и их связанных типов путем включения предложения where после родового список параметров. Предложение where состоит из ключевого слова where, затем разделенный запятыми список одного или нескольких требований.
Требования в предложении where указывают, что параметр типа наследуется от класса или соответствует протоколу или протоколу состав. Хотя предложение where предоставляет синтаксический сахар для выражая простые ограничения на параметры типа (например, T: Сопоставимый эквивалент T, где T: сравнимый и т.д.), Вы можете использовать его для обеспечения более сложных ограничений для параметров типа и связанных с ними типов. Например, вы можете выразить ограничения что общий тип T наследуется от класса C и соответствует протокол P как < T, где T: C, T: P > .
Итак, "Я" не может быть структурой или emum, которая кажется, что является позором. Предположительно, для этого есть причина для разработки языка. Сообщение об ошибке компилятора, безусловно, может быть более четким.
Ответ 3
Поскольку Foo
является существующим типом, вы можете просто расширить его таким образом:
struct Foo { // <== remove MyProtocol
let myVar: String
init(myVar: String) {
self.myVar = myVar
}
}
// extending the type
extension Foo: MyProtocol {
func bar() {
print(myVar)
}
}
Из Язык Swift для программирования (Swift 2.2):
Если вы определяете расширение для добавления новых функций к существующему типу, новая функциональность будет доступна во всех существующих экземплярах этого типа, даже если они были созданы до того, как было определено расширение.