Swift泛型和协议

Swift泛型和协议,swift,generics,protocols,Swift,Generics,Protocols,考虑到下面的情况,这将抛出一个编译时错误,说明协议无法坚持自身,并且只有struct/enum可以坚持协议。这似乎违背了在泛型中使用协议的目的。我试图理解为什么这不起作用,但是如果我删除泛型,把协议放在“Z”的位置,一切都好。它似乎与协议和泛型应该被允许的内容相反 **编辑以澄清问题:我需要获取一种可以转换到[String:MyProtocol]字典的Any类型,并将其传递到方法printEmprintEm必须使用泛型,因为它将实例化类Z的实例 protocol MyProtocol { i

考虑到下面的情况,这将抛出一个编译时错误,说明协议无法坚持自身,并且只有struct/enum可以坚持协议。这似乎违背了在泛型中使用协议的目的。我试图理解为什么这不起作用,但是如果我删除泛型,把协议放在“Z”的位置,一切都好。它似乎与协议和泛型应该被允许的内容相反

**编辑以澄清问题:我需要获取一种可以转换到
[String:MyProtocol]
字典的Any类型,并将其传递到方法
printEm
printEm
必须使用泛型,因为它将实例化类
Z
的实例

protocol MyProtocol {
  init()
  var whoAmI:String { get }
}

func genericPassing(unknownThing:Any) {
  let knownThing = unknownThing as? [String:MyProtocol]
  if(knownThing != nil){
    self.printEm(knownThing)
  }
}

func printEm<Z:MyProtocol>(theThings:[String:Z]) {
  let zCollection:[Z] = []
  for thing in theThings {
    print(thing.whoAmI)
    zCollection.append(Z())
  }
}
协议MyProtocol{
init()
var whoAmI:字符串{get}
}
func genericPassing(未知:任何){
let knownThing=未知为?[字符串:MyProtocol]
如果(知道!=无){
自我打印(了解)
}
}
func printEm(things:[String:Z]){
让zCollection:[Z]=[]
因为事情在想{
打印(thing.whoAmI)
zCollection.append(Z())
}
}
**编辑printEm以说明为什么需要通用

**编辑以获得更复杂的代码。这两个主要要求是使用泛型来调用Z(),以及能够以某种方式对其进行Any类型检查和/或强制转换,以便可以在泛型化方法中使用它

private func mergeUpdates<Z:RemoteDataSyncable>(source:inout Z, updates:[WritableKeyPath<Z, Any>:Any]) throws {
        for key in updates.keys {
            let value = updates[key]!
            let valueDict = value as? [String:[WritableKeyPath<RemoteDataSyncable, Any>:Any]]
            if(valueDict != nil) {
                var currentValueArray = source[keyPath: key] as? [RemoteDataSyncable]
                if(currentValueArray != nil) {
                    self.mergeUpdates(source: &currentValueArray!, updates: valueDict!)
                }
                else {
                    throw SyncError.TypeError
                }
            }
            else {
                source[keyPath: key] = value
            }
        }
    }
    
    private func mergeUpdates<Z:RemoteDataSyncable>(source:inout [Z], updates:[String:[WritableKeyPath<Z,Any>:Any]]) {
        for key in updates.keys {
            var currentObject = source.first { syncable -> Bool in
                return syncable.identifier == key
            }
            if(currentObject != nil) {
                try! self.mergeUpdates(source: &currentObject!, updates: updates[key]!)
            }
            else {
                var newSyncable = Z()
                try! self.mergeUpdates(source: &newSyncable, updates: updates[key]!)
                source.append(newSyncable)
            }
        }
    }
private func mergeUpdates(来源:inout Z,updates:[writeablekeypath:Any])抛出{
用于输入更新。密钥{
让值=更新[键]!
让valueDict=值为?[String:[WritableKeyPath:Any]]
如果(valueDict!=nil){
var currentValueArray=源[keyPath:key]为?[RemoteDataSyncable]
如果(currentValueArray!=nil){
self.mergeUpdates(源:¤tValueArray!,更新:valueDict!)
}
否则{
抛出SyncError.TypeError
}
}
否则{
source[keyPath:key]=值
}
}
}
private func mergeUpdates(源:inout[Z],更新:[String:[WritableKeyPath:Any]]{
用于输入更新。密钥{
var currentObject=source.first{syncable->Bool-in
返回syncable.identifier==键
}
if(currentObject!=nil){
试试!self.mergeUpdates(源:¤tObject!,更新:updates[key]!)
}
否则{
var newSyncable=Z()
试试!self.mergeUpdates(来源:&newSyncable,更新:updates[key]!)
source.append(新闻同步电缆)
}
}
}

这是一个完美的例子,说明了为什么协议不符合自身。在您的代码中,
Z
MyProtocol
,因此
Z()
MyProtocol()
。那怎么办?它是什么类型的?它有多大?然后不能将它们放入
[Z]
,因为它们可能是不同的类型

您的意思是传递任意MyProtocols并对每个元素的类型调用
init

func printEm(theThings:[String: MyProtocol]) {
    var zCollection:[MyProtocol] = []
    for thing in theThings.values {
        print(thing.whoAmI)
        zCollection.append(type(of: thing).init())
    }
}

当我建议使用闭包时,这就是我的意思。此更新程序可以接受任意引用WritableKeyPath,当您向其传递任何更新值时,它会将其分配给可以接受它的每个键路径。这有点没用,但显示了技术。(请记住,更新程序将保留该对象,因此这可能是您需要解决的问题。)

类更新程序{
私有(集合)var更新程序:[(任何)->()]=[]
func add(keyPath:ReferenceWritableKeyPath,在根目录下:根目录下){
updaters.append{中的值
如果让值=值为?值{
根[keyPath:keyPath]=值
}
}
}
func updateAll(带值:Any){
用于更新程序中的更新程序{
更新程序(值)
}
}
}
类客户端{
var updateMe:Int=0
}
让client=client()
让updater=updater()
add(keyPath:\.updateMe,on:client)
updater.updateAll(带:3)
client.updateMe//3

这段代码的关键教训是
add
上的泛型类型在编译时被
(Any)->()
闭包擦除(隐藏)。运行时
as?
检查是在闭包内完成的,在闭包中类型都是已知的。

(1)您想做什么?(2) 问题是什么?@matt我需要上面的两个方法,以避免抛出编译错误。更具体地说,我需要能够将具有协议的字典作为泛型,并将其传递到泛型方法中。因此,我需要能够将[String:MyProtocol]传递到func printEm(theThings;[String:Z]),这样我就可以处理[“key”].whoAmI以及Z()。除此之外,我还想理解为什么当前的实现不起作用,因为它似乎是泛型和协议应该能够处理的本质,并且在许多其他语言中也应该如此。正如错误所说,协议不符合它们自己,但您不需要它们。你的仿制药没用。摆脱它。这应该是
func-printEm(things:[String:MyProtocol])
“将[String:MyProtocol]传递到func-printEm(things;[String:Z])”-不,这不是Z的意思<代码>Z:MyProtocol表示“MyProtocol采纳者”。你可以通过
[String:What]
哪些内容符合我的协议。是的,我知道我可以这样做,但那不行。我将在上面进行调整,以说明为什么在我的具体情况下这不起作用。是否有可能获得用于
uknownThings
的泛型并将其作为
Z
传递?伙计,我对这一点非常兴奋,但不幸的是,它与我的用例不匹配。我可能从我的例子中提取了太多的复杂性。我继续添加了我的更复杂的示例,解释了为什么上面的示例无法解决我的问题。我没有“th”的实例
class Updater {
    private(set) var updaters: [(Any) -> ()] = []

    func add<Root, Value>(keyPath: ReferenceWritableKeyPath<Root, Value>, on root: Root) {
        updaters.append { value in
            if let value = value as? Value {
                root[keyPath: keyPath] = value
            }
        }
    }

    func updateAll(with value: Any) {
        for updater in updaters {
            updater(value)
        }
    }
}

class Client {
    var updateMe: Int = 0
}

let client = Client()

let updater = Updater()
updater.add(keyPath: \.updateMe, on: client)

updater.updateAll(with: 3)

client.updateMe // 3