[英]How to achieve object merging through generics in swift?
想象一下,我有一個班級編號:
class Number {
var val: Double?
}
並且有兩個類A
和B
實例。 現在假設我想通過類似的語句將B
合並到A
merge(B, into: A)
現在我當然可以寫這樣的函數:
func merge(from: Number, into: Number){
into.val = from.val
}
但這根本不可重復使用。 有沒有辦法可以編寫泛型合並類?
更新 :雖然一些答案提供了良好和可行的解決方案,但它們都不夠“通用”(這里的通用意味着非技術方式)。所以我看到了答案,我得到了一些靈感,這就是解決方案我現在正在考慮:使Number成為一個NSObject子類,並聲明所有可以合並為動態的屬性。 例如:
class Number: NSObject {
//Put the required init and initWithCoder: here
dynamic var val: Double?
}
然后聲明可合並類必須遵守的協議
protocol Mergeable: class {
var mergeablePropertyKeys:[String] {get}
}
然后聲明執行合並的全局函數:
func merge<U: Mergeable, Mergeable where U.Type == V.Type>(from: U, into:V){
for property in U.mergeablePropertyKeys {
V.setValue(U.valueForKey(property), property)
}
}
我知道這不會起作用,因為合並的參數不一定是NSObjects
。
merge
的參數都是NSObjects?
我不確定你的期望,但有通用的解決方案:
class Number<T> {
var val: T?
}
protocol Merge {
func merge(from: Self, into: Self)
}
extension Number: Merge {
func merge(from: Number, into: Number) {
into.val = from.val
}
}
讓我們像這樣定義一個HasValue
協議(僅適用於類)
protocol HasValue: class {
typealias T
var val: T? { get set }
}
現在我們可以定義一個泛型函數
func merge<U: HasValue, V:HasValue where U.T == V.T>(from: U, into:V) {
into.val = from.val
}
函數簽名中的約束可以保證這一點
HasValue
(因此是類) val
類型是等於的 class Number: HasValue {
var val: Double?
}
let one = Number()
one.val = 1
let two = Number()
two.val = 2
merge(one, into: two)
print(two.val) // Optional(1.0)
我並沒有將Merge
的2個參數限制為具有相同的類型,我只是檢查2個參數的val
屬性必須具有相同的類型。
所以我們也可以合並具有相同類型的val的不同類的不同實例
class Phone: HasValue {
var val: Int?
}
class Computer: HasValue {
var val: Int?
}
let iPhone = Phone()
iPhone.val = 10
let iMac = Computer()
iMac.val = 9
merge(iPhone, into: iMac)
print(iMac.val) // Optional(10)
class Box<S>: HasValue {
var val: S?
}
let boxOfString = Box<String>()
boxOfString.val = "hello world"
let boxOfInt = Box<Int>()
boxOfInt.val = 12
merge(boxOfString, into: boxOfInt) // << compile error
let boxOfWords = Box<String>()
boxOfWords.val = "What a wonderful world"
merge(boxOfString, into: boxOfWords)
print(boxOfWords.val) // Optional("hello world")
聽起來你想要的是一個使用反射來合並屬性的泛型函數。 Swift中的反射是有限的,但使用MirrorType是可行的。 我之前使用過這個方法在swift中構建一個通用的json解析器 - 你可以做類似的事情但不是解析json字典到屬性映射你的兩個對象的屬性。
使用反射在swift中執行此操作的示例:
func merge<T>(itemToMerge:T) {
let mirrorSelf = Mirror(reflecting: self)
let mirrorItemToMerge = Mirror(reflecting: itemToMerge)
for mirrorSelfItem in mirrorSelf.children {
// Loop through items in mirrorItemToMerge.
for mirrorImageItem in mirrorItemToMerge.children {
// If you have a parameter who's name is a match, map the value
// OR You could add any custom mapping logic you need for your specific use case
if mirrorSelfItem.label == mirrorImageItem.label {
// To set values, use self.setValue(valueToSet, forKey: propertyName)
self.setValue(mirrorImageItem.value as? AnyObject, forKey: mirrorImageItem.label!)
}
}
}
}
這假設定義merge方法的對象是NSObject的子類(因此它可以利用NSKeyValueCoding)。 你也可以使這個靜態方法可以合並任何NSObject類型的任何2個對象:
static func merge<T1: NSObject, T2: NSObject>(itemChanging:T1, itemToMerge:T2) {
let mirrorSelf = Mirror(reflecting: itemChanging)
let mirrorItemToMerge = Mirror(reflecting: itemToMerge)
for mirrorSelfItem in mirrorSelf.children {
// Loop through items in mirrorItemToMerge.
for mirrorImageItem in mirrorItemToMerge.children {
// If you have a parameter who's name is a match, map the value
// OR You could add any custom mapping logic you need for your specific use case
if mirrorSelfItem.label == mirrorImageItem.label {
// To set values, use self.setValue(valueToSet, forKey: propertyName)
self.setValue(mirrorImageItem.value as? AnyObject, forKey: mirrorImageItem.label!)
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.