2017-08-07 83 views
0

我有一個具有類型約束的通用屬性的自定義協議的結構。該協議是空的,其目的無非是爲了保證某些類型的唯一要素可以存儲在這個通用變量:swift修改結構的通用屬性

protocol MyProtocol {} 

struct TypeA: MyProtocol { 
    someProperty: String 
} 

struct TypeB: MyProtocol { 
    someOtherProperty: Int 
} 

var a = TypeA(someProperty: "text") 
var b = TypeB(someOtherProperty: 5) 

// The following is the actual struct in question: 

struct Item { 
    var something: Int 
    var elementOfTypeAorB: MyProtocol 
} 

var firstItem = Item(something: 10, elementOfTypeAorB: a) 
var secondItem = Item(something: 3, elementOfTypeAorB: b) 

當我想訪問我有我的「基地」結構類型A或類型B的性能將它們轉換成原始類型:

print((secondItem.elementOfTypeAorB as! TypeB).someOtherProperty) // 5 

我現在要來檢查,如果該物業的TypeB是的,如果是,改變價值FUNC,因此函數體可以讀取:

if type(of: secondItem.elementOfTypeAorB) == TypeB.self { 
    (firstItem.elementOfTypeAorB as! TypeB).someOtherProperty+=5 
} 

但我得到一個錯誤信息:變異操作的左邊有不可改變的類型「詮釋」

如果我改變我的類型A和類型B結構要上課,所以我可以做這樣的:

if type(of: secondItem.elementOfTypeAorB) == TypeB.self { 
    var modify = (secondItem.elementOfTypeAorB as! TypeB) 
    modify.someOtherProperty+=5 
} 

如類是引用類型,secondItem的原始someOtherProperty ...將被修改,但是甚至一個.OtherProperty也會被改變(後者並不重要,但是,因爲a和b在這裏只是幫助變量。

但是,如果我想留在結構的領域,我發現改變泛型elementOfTypeAorB的屬性的唯一方法是將它們向下轉換爲一個新變量,改變這個變量並將整個變量寫回更高 - 電平結構,如:

secondItem.elementOfTypeAorB = modify 

這工作得很好,但在我的實際項目的類型A和類型B結構持有不僅一個單一的財產,所以,我想每一次改變只是其中的一個不得不做整個結構的副本,然後再次用這個修改的副本替換整個結構對我來說似乎相當昂貴。

那麼,有沒有另一種方法來改變我只是沒有遇到的通用結構的屬性呢?

回答

1

您必須執行可選的轉換:而不是檢查使用type(of: value) == Type類型

if var elementA = elementOfTypeAorB as? TypeA { 
    elementA.someProperty = ... 
    elementOfTypeAorB = elementA 
} else if var elementB = elementOfTypeAorB as? TypeB { 
    elementB.someOtherProperty = ... 
    elementOfTypeAorB = elementA 
} 

此外,你應該使用value is Type

或者,考慮使用具有關聯值的枚舉。它更適合您的用例,因爲應該使用協議來定義可用於與實例交互的接口。

enum AorB { 
    case a(TypeA) 
    case b(TypeB) 
} 

這允許您將變量的類型限制爲TypeA和TypeB。

然後,您可以使用switch caseif case聲明解開值:

switch elementOfTypeAorB { 
    case .a(var elementA): 
     elementA.someProperty = ... 
     elementOfTypeAorB = .a(elementA) 
    case .b(var elementB): 
     elementB.someOtherProperty = ... 
     elementOfTypeAorB = .b(elementB) 
} 
+1

好吧,我會看看與枚舉,而不是協議的解決方案,但答案的其餘部分基本上是:唯一解決辦法就是按照我在最後2段中所寫的內容執行操作:將副本下載到新的變量,然後將值更改爲原始重寫,對不對? – MassMover