2017-02-17 191 views
0

看到奇怪的泛型行为,这导致我相信我错过了我理解中的某些东西。Swift:运行时泛型类型推断

我正在使用以下方法循环抛出JSON响应并调用泛型方法。 UserCardEcard全部来自IDObject继承,这反过来从Object(一类域)继承

let props:[(label:String, type:IDObject.Type)] = [ 
    (label: "deletedUsers", type: User.self), 
    (label: "deletedCards", type: Card.self), 
    (label: "deletedECards", type: Ecard.self) 
] 

for prop in props { 
    if let ids = json[prop.label].arrayObject as? [Int], ids.count > 0 { 
     DataManager.shared.delete(prop.type, ids: ids) 
    } 
} 

func delete<T:IDObject>(_ type:T.Type, ids:[Int]) { 
    guard ids.count > 0 else { return } 
    if let objectsToDelete = objects(type, where: NSPredicate(format: "identifier IN %@", ids)) { 
     delete(objectsToDelete) 
    } 
} 

func delete<T:Object>(_ objects:Results<T>) { 
    guard objects.count > 0 else { return } 
    do { 
     let realm = try Realm() 
     try realm.write { 
      realm.delete(objects) 
     } 
    } catch { 
     print(error) 
    } 
} 

delete(_ type:T.Type, ids:[Int])功能不能推断泛型类型这种方式。

但是,展开for prop in props循环按预期工作。

if let userIds = json["deletedUsers"].arrayObject as? [Int], userIds.count > 0 { 
    DataManager.shared.delete(User.self, ids: userIds) 
} 

不要只泛型在编译的时候工作,或者是有没有办法在运行时动态处理呢?

+0

究竟你“的意思*了'删除'函数不能通过这种方式推断泛型*“?你得到一个编译器错误? (如果是的话,在哪里?)你错过了'DataManager.shared.delete(prop.type,ids:ids')的右括号,除非你用单个参数重载'delete',否则不能调用它一个参数('delete(objectsToDelete)')。请你提供一个[mcve],包括预期的行为和实际行为? – Hamish

+0

@Hamish整个代码库非常大,我不能随意分享它我已经在这里大量地编辑了它,并且我已经修复了缺失的右括号,'delete'确实被重载了 - 'delete(:)'方法需要一个'Results '''IDObject'继承自'Object'。我看到的行为是在删除(objects :)方法,objects.count == 0 – dmorrow

+0

你不需要共享整个代码库 - 只有一个最小的自包含的例子,重现相同的问题。是' DataManager.shared.delete'应该引用'delete(_:ids:)'?什么是对象(_:where:)'return?(你没有甚至必须显示功能,只是模拟一个功能,重现相同的问题)。 “ids”甚至与问题有关吗? (如果没有,请将其删除)。 – Hamish

回答

1

泛型在编译时被评估并被分配一个具体的类型。没有“运行时类型推断”这样的东西。

我想你想的主要变化是:

func delete(_ type:IDObject.Type, ids:[Int]) { 

你不想专注于type这个功能,你只是想通过type

不清楚objects(_:where:)返回什么,所以这可能会破坏您的delete方法。您可能需要使它不那么具体:

func delete(_ objects:Results<Object>) { 

(这是不是子类型的灵丹妙药;我假设objects(_:where:)恰好返回Results<Object>

+0

我认为通过“在运行时键入推论”他意味着类似[this](http://stackoverflow.com/a/30945263/5175709)阅读**协议可以选择静态或动态调度。**他基本上是指静态与动态调度。 – Honey

+0

我可能在这里错过了一些东西,但我没有看到如何改变'type'参数的静态类型将会改变OP代码的运行时行为(考虑到当他调用delete时(假设它实际上是DataManager.shared .delete'),'T'已被推断为'IDObject')。另请注意,泛型仅作为编译器优化专用。 – Hamish

+0

它可能已经被推断为'IDObject',但专业上它是最好的混乱,因为读者可能认为更多的正在发生的事情(这是很难测试,因为此代码不能编译)。 “专业化”并不一定意味着编译器编写了一个独特的函数版本。 '阵列'是Array'的'专业化'上Int',不管它是如何由编译器实现。 –