Как соответствовать установленным и полученным переменным протокола?
Я играю с протоколами и как их соблюдать.
protocol Human {
var height: Int {get set}
}
struct boy : Human {
var height: Int {return 5} // error!
}
Я пытаюсь изучить различные способы, которыми я могу реализовать набор и получить.
Однако приведенный выше код выдает следующую ошибку:
тип "мальчик" не соответствует протоколу "Человек"
Однако при написании ниже не будет ошибок:
struct boy : Human {
var height = 5 // no error
}
Я не понимаю ни разницы, ни того, что именно нужно реализовать, когда вы также можете установить переменную. Я изучал различные вопросы и учебные пособия, но все они просто пишут и идут без каких-либо более глубоких объяснений.
EDIT:
убедитесь, что вы видите Imanou ответ здесь. Это сильно объясняет разные сценарии.
Ответы
Ответ 1
Из Swift Reference:
Требования к свойствам
...
Протокол не указывает, должно ли свойство быть сохраненным свойством или вычисленным свойством - оно указывает только требуемое имя и тип свойства.
...
Требования к свойствам всегда объявляются как переменные свойства с префиксом ключевого слова var
. Получаемые и настраиваемые свойства указываются путем записи { get set }
после их объявления типа, а свойства gettable указываются путем записи { get }
.
В вашем случае
var height: Int {return 5} // error!
- вычисленное свойство, которое можно получить только, это
ярлык для
var height: Int {
get {
return 5
}
}
Но для протокола Human
требуется свойство, которое можно получить и настроить.
Вы можете либо соответствовать сохраненной переменной (как вы заметили):
struct Boy: Human {
var height = 5
}
или с вычисленным свойством, которое имеет как getter, так и setter:
struct Boy: Human {
var height: Int {
get {
return 5
}
set(newValue) {
// ... do whatever is appropriate ...
}
}
}
Ответ 2
Предпосылка:
Зайдите на игровую площадку и просто напишите фрагмент ниже:
var height: Int {
get {
return 5
}
}
или аналогично:
var height: Int {
return 5
}
Попробуйте напечатать значение height
, очевидно, работает. Пока все хорошо
print(height) // prints 5
Однако, если вы попытаетесь установить его новое значение, вы получите сообщение об ошибке:
height = 8 // ERROR
ошибка: нельзя присвоить значению: свойство 'height' доступно только для получения
Ответ:
Основываясь на ответе Мартина, я сначала написал:
set(newValue) {
height = newValue
}
Который изрядно нагрузил мою память и привел меня к этому вопросу. Пожалуйста, взгляните. Тогда я решил, что написать, и понял, что если вы не хотите делать что-то особенное, вы не должны использовать вычисляемые свойства, а вместо этого вы должны просто использовать обычные сохраненные свойства.
Поэтому я написал похожий код
protocol Human {
var height: Float {get set}
}
struct Boy: Human {
// inch
var USheight : Float
// cm
var height: Float {
get {
return 2.54 * USheight
}
set(newValue) {
USheight = newValue/2.54
}
}
}
// 5 ft person
var person = Boy(USheight: 60)
// interestingly the initializer is 'only' based on stored properties because they
// initialize computed properties.
// equals to 152cm person
print(person.height) // 152.4
Совет для профессионалов: когда вы должны сделать свои свойства доступными только для чтения?
Обычно, если вы делаете свойство доступным только для чтения, то есть { get }
, потому что эти свойства вычисляются, и вы не хотите, чтобы объект управлял им.
Пример у вас есть объект JSON. Он имеет несколько больших объектов, таких как:
JSONData
- userInfo (name, address, age)
- devices (iPads, iPhones, Mac books)
- credentials (basic iCloud, pro iCloud, celebrity)
делая роль доступной только для чтения, вы только позволяете серверу сообщать кодовой базе роль пользователя.
protocol Credentials {
var role: String { get }
init(person: Person)
}
class Person {
var userInfo: String
var devices: [String]
var creds: Credentials {
Credentials(person: self)
}
init(userInfo: userInfo, devices: [String]) {
self.userInfo = userInfo
self.devices = devices
}
}