2014-06-25 51 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 
    }

現在即使數組是由結構組成的,我們也可以輕鬆地進行賦值。