2017-02-22 14 views
0

Начну с небольших примеров кода, сделанных как можно проще, чтобы подвести итог этой проблеме.Как выполнить «необязательную разворачивание» функции с использованием общих параметров

Скажу, у меня есть функция, определенная следующим образом:

func doSomething<T>(using f: (String, (T) -> Void) -> Void, key: String) { 
    f("test", { 
     object in 
     // do something with object using key 
     //... 
    }) 

} 

Я получил кучу автогенерируемых классов с методами класса для Exemple:

class MyClass { 
    var prop1: String = "" 
} 

class MyClassAPI { 

    class func f1(param: String, completion: (MyClass) -> Void) { 
     let mc = MyClass() 
     mc.prop1 = "hello" 
     completion(mc) 
    } 
} 

Затем я получил целый набор ключевых/функциональных пар в словаре:

// Any because of cast problem ! 
let keyFunctions: [String: Any] = [ 
    "first" : MyClassAPI.f1, 
    "second" : MySecondClassAPI.f2, 
    "third" : MyThirdClassAPI.f3 
    //... 
] 

Наконец, я буду перебирать все ключи/f соборование позвонить doSomething:

for (k, f) in keyFunctions { 
    // This line doesn't work as the compiler complain about typing errors 
    doSomething(using: f, key: k) 
} 

Проблема я столкнулся в том, что я не могу бросить свои функции на правильный тип, чтобы передать их doSomething:

Xcode предполагают, чтобы заставить актеров с помощью f as! (String, (_) ->()) -> Void затем дает я ошибка, _ не тип.

Я старался быть более разрешительным, используя if let uf = f as? (String, (Any) -> Void) -> Void без каких-либо шансов.

Я прочитал все страницы дженериков руководства Swift без каких-либо намеков на то, как этого добиться.

Пожалуйста, дайте мне знать о любом существующем способе выполнения таких вещей с использованием универсальности.

+0

Они называются более высокие kinded типы. Свифт их не поддерживает. – Alexander

+1

Выполняют ли функции 'f1',' f2' и 'f3' в вашем словаре разные классы? Могут ли они хотя бы соответствовать одному протоколу? – Dmitry

+0

@ Dimitry Нет, они не возвращаются из разных классов, на самом деле одним из их параметров является замыкание, причем каждый из них принимает другой тип в качестве параметра. Я думаю, что мне нужно будет привести их в соответствие с протоколом, спасибо – dulgan

ответ

1

Вместо Any сделать более конкретный тип для блока

let keyFunctions: [String: (String) -> Any] 

Тогда, по крайней мере, ваш будет компилировать и doSomething будет называться. Тем не менее, нет смысла делать его общим, так как T всегда будет Any. Если doSomething опирается на общее поведение между вашими классами, тогда было бы целесообразно определить протокол для всех из них.

Если вы действительно хотите иметь информацию о классах, то вы можете ввести неофициальный общий класс, который будет держать эту информацию:

class Wrap { 
    var resultType: Any.Type 
    let f: (String) -> Any 

    init<T>(_ f: @escaping (String) -> T) { 
     self.f = f 
     resultType = T.self 
    } 
} 

let keyFunctions: [String: Wrap] = [ 
    "first" : Wrap(MyClassAPI.f1), 
    "second" : Wrap(MySecondClassAPI.f2) 
] 

Но resultType не может быть использован в отливке позже, хотя.

+0

Я дам ему выстрел, но я не буду Думаю, что я смогу вызвать функции с соответствующими параметрами в моей функции doSomething. Я изменил свой код, чтобы быть ближе к моей реальной проблеме, пожалуйста, дайте мне знать, если это что-то изменит или нет. – dulgan

+0

Мне удалось заставить его работать, поскольку мне не нужно было знать класс объектов в блоке завершения (см. отредактированный вопрос), +1 для идеи обертки – dulgan

0

я наконец сделал это так:

func doSomething<T>(using f: (String, (Any) -> Void, key: String, type: T.Type) -> Void, key: String) { 
    f("test", { 
     object in 
     guard let o as? type else { return } 
     // do something with o using key 
     //... 
    }) 
} 

let keyFunctions: [String: (String, (Any) -> Void)] = [ 
    "first" : MyClassAPI.f1, 
    "second" : MySecondClassAPI.f2, 
    "third" : MyThirdClassAPI.f3 
    //... 

]

Смежные вопросы