在协议中指定一个可设置的 property/variable
Specify a settable property/variable in a protocol
我希望我的协议声明有 read/write 属性 可用。我已经尝试过了,但这不起作用:
protocol EdibleThing {
var eaten: Bool { get set }
}
class Pickle: EdibleThing { var eaten = false }
class RusticGrapefruit: EdibleThing { var eaten = false }
class Jar {
let contents: [EdibleThing] = [Pickle(), RusticGrapefruit()]
var nextItem: EdibleThing {
return contents.last ?? Pickle() // Lazy pickle generation technology
}
func eat() {
let food = nextItem
food.eaten = true // (!) ERROR: Cannot assign to result of this expression
}
}
我做错了什么?我想我已经声明协议有一个名为 eaten
的 get/set 变量,那么为什么我不能设置它?
你正在变异 food
。
将 let food = nextItem
替换为 var food = nextItem
该协议可能由 classes 和结构实现 - 这会阻止您更改 class 实例的内部状态或使用不可变变量实现该协议的结构。
要解决此问题,您必须将 food
变量声明为可变的:
func eat() {
var food = nextItem
food.eaten = true // (!) ERROR: Cannot assign to result of this expression
}
或声明 EdibleThing
协议只能由 classes 实现:
protocol EdibleThing : class {
var eaten: Bool { get set }
}
请注意,发生这种情况是因为 food
是 EdibleThing
类型的变量 - 编译器不知道实际实例是值类型还是引用类型,因此会引发错误。如果你让它成为一个 class 类型的变量,像这样:
let food: Pickle = nextItem as! Pickle
编译器毫不含糊地知道它是一个引用类型,在这种情况下它允许赋值。但我想这会破坏你的应用程序逻辑......所以把它当作一个例子
问题是您不能在 let
.
定义的值类型上改变 属性
即使 RusticGrapefruit
和 Pickle
都是 class 实现(引用类型),协议也可以像结构一样分配给值类型。编译器检测到潜在问题并阻止我们。
两种解决方案:
- 将
let
更改为 var
(在我的例子中,这意味着更改大量引用此类对象的代码。此外,我喜欢语义值和可能的编译器优化let
)
- 声明协议仅对 classes 有效:
protocol EdibleThing: class { }
我希望我的协议声明有 read/write 属性 可用。我已经尝试过了,但这不起作用:
protocol EdibleThing {
var eaten: Bool { get set }
}
class Pickle: EdibleThing { var eaten = false }
class RusticGrapefruit: EdibleThing { var eaten = false }
class Jar {
let contents: [EdibleThing] = [Pickle(), RusticGrapefruit()]
var nextItem: EdibleThing {
return contents.last ?? Pickle() // Lazy pickle generation technology
}
func eat() {
let food = nextItem
food.eaten = true // (!) ERROR: Cannot assign to result of this expression
}
}
我做错了什么?我想我已经声明协议有一个名为 eaten
的 get/set 变量,那么为什么我不能设置它?
你正在变异 food
。
将 let food = nextItem
替换为 var food = nextItem
该协议可能由 classes 和结构实现 - 这会阻止您更改 class 实例的内部状态或使用不可变变量实现该协议的结构。
要解决此问题,您必须将 food
变量声明为可变的:
func eat() {
var food = nextItem
food.eaten = true // (!) ERROR: Cannot assign to result of this expression
}
或声明 EdibleThing
协议只能由 classes 实现:
protocol EdibleThing : class {
var eaten: Bool { get set }
}
请注意,发生这种情况是因为 food
是 EdibleThing
类型的变量 - 编译器不知道实际实例是值类型还是引用类型,因此会引发错误。如果你让它成为一个 class 类型的变量,像这样:
let food: Pickle = nextItem as! Pickle
编译器毫不含糊地知道它是一个引用类型,在这种情况下它允许赋值。但我想这会破坏你的应用程序逻辑......所以把它当作一个例子
问题是您不能在 let
.
即使 RusticGrapefruit
和 Pickle
都是 class 实现(引用类型),协议也可以像结构一样分配给值类型。编译器检测到潜在问题并阻止我们。
两种解决方案:
- 将
let
更改为var
(在我的例子中,这意味着更改大量引用此类对象的代码。此外,我喜欢语义值和可能的编译器优化let
) - 声明协议仅对 classes 有效:
protocol EdibleThing: class { }