簡體   English   中英

如何通過swift中的泛型實現對象合並?

[英]How to achieve object merging through generics in swift?

想象一下,我有一個班級編號:

class Number {
    var val: Double?
}

並且有兩個類AB實例。 現在假設我想通過類似的語句將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
}

函數簽名中的約束可以保證這一點

  1. 兩個參數都符合HasValue (因此是類)
  2. 兩個參數的val類型是等於的

場景1:params具有相同的類型

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)

場景2:params具有不同的類型,但它們的值具有相同的類型

我並沒有將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)

場景3:params具有泛型類型

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM