2014-06-25 56 views
2

我旁边继承:协议的斯威夫特数组类型的对象

protocol P { 
    var a : Int { get set } 
} 

class C : P { 
    var a : Int 
    ... 
} 

然后我想创建广义阵列,并通过它与一些动作重复:

class Main { 
    var array : Array<Proto> 
    var inst : Proto 
    ... 
    func foo() { 
     array.append(C(a:10)) 
     for obj in array { 
      obj.a = 20  //Error: Cannot assign to the result of this expression 
     } 

     inst = C(a:10) 
     inst.a = 20   //Works correctly 

     for var i = 0; i < arr.count; ++i { 
      inst = arr[i] 
      inst.a = 20  //No problem even here 
     } 
    } 
} 

如果我投:(OBJ作为C).a = 20 - 那么一切都很好。 有人可以解释这种行为吗?

回答

1

问题是,for-in循环不允许修改迭代项目。从documentation

注意

指数常数只存在循环的范围之内。如果要在循环完成后检查索引的值,或者如果要将其值作为变量而不是常量进行处理,则必须在循环中使用它之前自行声明它。

你可以尝试以下方法:

for obj in array { 
     var c = obj 
     c.a = 20  // This should work as c is a mutable copy of obj 
    } 

补充:

注意什么@ikuramedia说是正确的。上面的代码掩盖其中obj是值类型的情况,在这种情况下c将成为它的副本,并且值obj中的数组实际上不会被修改为

+0

这不是一个好的答案。最好确保我们有一个班级类型。这个甚至不会崩溃。 – Sulthan

1

协议可以平等地应用于Classes,Structs和Enums,所以在你的代码中编译器不能假定obj是一个对象类型。因此,它不知道obj是引用类型还是值类型。如果它是一个值类型,那么你不能在没有变异方法的情况下改变对象,因此它假定你的代码不是类型正确的,并且不能编译。

你既可以声明数组为类型AnyObject的符合原,或者你可以在向下转换为循环迭代:for obj as! C in array

+1

或协议为'@ class_protocol'。 – Sulthan

+0

是的,这也应该工作! – ikuramedia

+0

@ikuramedia:你将如何去解释'declar数组是否符合Proto'的AnyObject类型? – Senseful

1

问题已经由他人进行了说明 - 总结:

  1. 迭代总是恒定
  2. 协议可由两个类和结构适于

如果吨他的协议是通过一个结构进行调整的,分配会失败,因为我们不能分配常量结构的属性(并且迭代器obj是常量)。

为了解决这个问题,我们有两个基本的选择:

  1. 声明协议的方式,它不能被结构

    @class_protocol protocol P {

  2. 修改迭代的工作进行调整结构和类别

    for i in indices(array) { 
        array[i].a = 20 
    }

现在即使数组是由结构组成的,我们也可以轻松地进行赋值。