在协议中指定可设置的属性/变量

时间:2015-06-17 08:40:24

标签: swift protocols

我希望我的协议声明有可用的读/写属性。我尝试过,但这不起作用:

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 var,为什么我不能设置它?

3 个答案:

答案 0 :(得分:2)

协议可以由类和结构实现 - 这可以防止您使用不可变变量更改实现该协议的类或结构的实例的内部状态。

要解决此问题,您必须将food变量声明为可变:

func eat() {
    var food = nextItem
    food.eaten = true // (!) ERROR: Cannot assign to result of this expression
}

或声明EdibleThing协议只能由类实现:

protocol EdibleThing : class {
    var eaten: Bool { get set }
}  

请注意,这是因为foodEdibleThing类型的变量 - 编译器不知道实际实例是值还是引用类型,因此会引发错误。如果你把它变成类类型的变量,就像这样:

let food: Pickle = nextItem as! Pickle

编译器在没有任何歧义的情况下知道它是引用类型,并且在这种情况下它允许赋值。但我想这会打破你的应用程序逻辑...所以请将其视为一个例子

答案 1 :(得分:1)

你正在改变food

let food = nextItem替换为var food = nextItem

答案 2 :(得分:1)

问题在于,您无法改变由let定义的值类型的属性。

尽管RusticGrapefruitPickle都是类实现(引用类型),但协议可以分配给类似结构的值类型。编译器检测到潜在问题并阻止我们。

两种解决方案:

  1. let更改为var(在我的情况下,这将意味着更改引用此类对象的大量代码。此外,我喜欢{{的语义值和可能的编译器优化1}})
  2. 声明协议仅对类有效:let