Подтвердить что ты не робот

Расширения протокола в 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?

4b9b3361

Ответ 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):

Если вы определяете расширение для добавления новых функций к существующему типу, новая функциональность будет доступна во всех существующих экземплярах этого типа, даже если они были созданы до того, как было определено расширение.