Расширение протокола Swift: невозможно присвоить свойству: свойство '' доступно только для получения - PullRequest
0 голосов
/ 10 января 2019

Мне кажется, я не понимаю, как должны работать расширения протокола.

Я пробовал это:

protocol P {
    var h: [String: Any] { set get }
}

extension P {
    var h: [String: Any] {
        get {
            return [:]
        }
        set {}
    }
}

struct S: P {   
    init() {
        self.h = ["o": "o"]
    }
}

Моя цель состоит в том, чтобы S имел свойства P и не нуждался в его повторном объявлении в определении структуры.

Однако, когда я создаю let s = S(), s.h всегда равен [:], а не ["o":"o"].

Конечно, это потому, что мой сеттер пуст, но я не знаю, как сделать то, чего я хочу достичь.

Спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Вы были близки, вам просто нужно переопределить переменную h в S Struct

protocol P {
    var h: [String: Any] { set get }
}

extension P {
    var h: [String: Any] {
        get {
            return [:]
        }
        set {}
    }
}

struct S: P {
    var h: [String: Any]

    init() {
        self.h = ["o": "o"]
    }
}

let s = S()
print(s.h) // ["o": "o"]
0 голосов
/ 10 января 2019

Моя цель состоит в том, чтобы S обладал свойствами P и ему не нужно было повторно объявлять его в определении структуры.

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

Хорошо, если вам не нужно хранилище, тогда расширение может просто возвращать значения, как у вас. Но вы не можете вернуть вычисленные значения, а также иметь хранилище. То, что вы пытаетесь сделать, невозможно. Ты думаешь о классах, а не о протоколах. (Если вам нужны классы, это нормально. Используйте классы. С ними все в порядке.)

Хороший способ подумать о том, почему это невозможно в Swift, - рассмотреть следующий случай. Предположим, ваш протокол P существует в какой-то форме, которая достигает того, что вы хотите. Теперь в одном модуле мы определяем:

struct S {}

Эта структура не требует хранения. Любые вызовы S() в этом модуле ничего не выделяют. (В качестве альтернативы присвойте S некоторые свойства, и он выделит определенный объем памяти.)

Теперь в каком-то другом модуле расширьте S, чтобы соответствовать P:

extension S: P {}

Куда пойдет хранилище для h? Экземпляры могут уже существовать в тот момент, когда это расширение даже загружено. Что делать, если существует несколько протоколов, которые требуют дополнительного хранилища, и все они подключены к S Какими смещениями в структуре S должны быть эти свойства? Порядок будет очень важен для скомпилированного кода. Это не невозможно решить (ObjC делает это, используя технику, называемую ассоциированными объектами), но это большое дополнение к языку, которое предотвращает ряд важных оптимизаций, а Swift так не делает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...