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

Swift 在协议中指定可设置的属性/变量,swift,protocols,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()

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

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
  }
}

我做错了什么?我想我已经声明了这个协议有一个get/set变量,名为
eat
,那么为什么我不能设置它呢?

你在变异
食物


let food=nextItem
替换为
var food=nextItem
你正在变异
食品


let food=nextItem
替换为
var food=nextItem

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

要解决此问题,您必须将
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 }
}  
请注意,发生这种情况是因为
food
EdibleThing
类型的变量-编译器不知道实际实例是值类型还是引用类型,因此会引发错误。如果将其设置为类类型的变量,如下所示:

let food: Pickle = nextItem as! Pickle

编译器毫不含糊地知道它是引用类型,在这种情况下,它允许赋值。但我想这打破了你的应用程序逻辑。。。因此,作为一个例子,

协议可以由类和结构来实现,它阻止了使用一个不可变的变量来改变一个类的实例的内部状态或实现该协议的结构。 要解决此问题,您必须将
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 }
}  
请注意,发生这种情况是因为
food
EdibleThing
类型的变量-编译器不知道实际实例是值类型还是引用类型,因此会引发错误。如果将其设置为类类型的变量,如下所示:

let food: Pickle = nextItem as! Pickle

编译器毫不含糊地知道它是引用类型,在这种情况下,它允许赋值。但我想这打破了你的应用程序逻辑。。。因此,作为一个例子,

问题是,您不能在由<代码>定义的值类型上改变属性。 即使
rusticgrapefrait
Pickle
都是类实现(引用类型),协议也可以被分配给一个值类型,比如结构。编译器检测到一个潜在的问题并阻止我们

两种解决方案:

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

  • 问题在于,您无法对由
    let
    定义的值类型上的属性进行变异

    即使
    rusticgrapefrait
    Pickle
    都是类实现(引用类型),协议也可以被分配给一个值类型,比如结构。编译器检测到一个潜在的问题并阻止我们

    两种解决方案:

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

  • 我还尝试了更直接的访问:
    func eat(food:EdibleThing){food.eat=true}//错误:无法在“food”中指定“eat”
    可能与.Martin的重复项非常相似。我的案例要简洁得多,我认为答案也是如此。这是相同的问题和相同的解决方案……我还尝试了更直接的访问:
    func eat(food:edibleething){food.eat=true}//错误:无法在“food”中指定“eated”
    可能重复的。非常类似于Martin。我的案例要简洁得多,我认为答案也是如此。这是同样的问题,同样的解决方案……嗯?但是我可以将类实例分配给
    let
    vars一整天都没有问题,并修改它们的属性。协议类型是否可以由类或结构实现,但它不知道?EdibleThing也可能是结构,嗯@Antonio更快;-)嗯?但是我可以将类实例分配给
    let
    vars一整天都没有问题,并修改它们的属性。协议类型是否可以由类或结构实现,但它不知道?EdibleThing也可能是结构,嗯@Antonio更快;-)感谢托马斯为我指明了正确的方向。哦,还有安东尼奥!感谢托马斯为我指明了正确的方向。哦,还有安东尼奥!有关于这门课的文件吗?我在Swift书籍的协议部分中没有看到它们。它在协议章节中:它肯定不在“Swift:一种编程语言”iBooks书籍中(通过搜索
    :class
    SomeClassOnlyProtocol
    进行验证)。我不想再把它当作参考了,老是用过时的东西咬我。有关于这门课的文档吗?我在Swift书籍的协议部分中没有看到它们。它在协议章节中:它肯定不在“Swift:一种编程语言”iBooks书籍中(通过搜索
    :class
    SomeClassOnlyProtocol
    进行验证)。我不会再把它当作参考了,继续用过时的东西咬我。