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