/ / Swift створює екземпляр неправильного типу при використанні родової функції із закриттям - swift, generics, closals

Swift створює екземпляр неправильного типу, використовуючи загальну функцію з закриттям - швидкі, генерики, закриття

Я намагаюся створити загальну функцію, яка приймає закриття як параметр. У мене, проте, виникає проблема, тому для усунення проблеми я створив наступний код, який можна запустити на ігровому майданчику.

class BaseClass {
init(message: String) {
println("Base class says: " + message)
}

func getMyName() -> String {
return "BaseClass"
}
}

class SubClass: BaseClass {
override init(message: String) {
println("Subclass says: " + message)
super.init(message: message)
}

override func getMyName() -> String {
return "SubClass"
}

func specialAbility() {
println("only I can do this!")
}
}

func makeInstance<T: BaseClass>(callback: (T -> Void)?) {
callback?(T(message: "hello"))
}

makeInstance() {
(instance: SubClass) in
println("makeInstance1 built a " + instance.getMyName())
println("I think it is a (_stdlib_getDemangledTypeName(instance))")

//instance.specialAbility() - uncommenting this throws EXC_BAD_ACCESS at runtime
}

makeInstance() {
(instance: BaseClass) in
println("makeInstance2 built a " + instance.getMyName())
println("I think it is a (_stdlib_getDemangledTypeName(instance))")
}

Цей код дає такий вихід:

Base class says: hello
makeInstance1 built a BaseClass
I think it is a __lldb_expr_89.SubClass
Base class says: hello
makeInstance2 built a BaseClass
I think it is a __lldb_expr_89.BaseClass

Swift не дозволяє чітко вказати типу виклику функції (наприклад, makeInstance), тому я очікую, що компілятор виведе його з типу закриття в виклику. Здається, щоразу створює екземпляр BaseClass. Ініціалізатор SubClass не викликається, і його члени з'являються бути таким, як BaseClass.

Смію сказати, що це здається помилкою у Свіфта; якщо виспробуйте отримати доступ до члена SubClass під час першого закриття, у компілятора немає проблем з цим, але під час виконання викид викидається (див. мій коментар у коді).

Будь-які ідеї, як я можу обійти це? Якщо це не зрозуміло, я б хотів створити підклас BaseClass, коли закриття очікує його.

Відповіді:

2 для відповіді № 1

Я фактично просто змінив ваші ініціалізатори на такі, як це потрібно:

class BaseClass {
required init(message: String) {
println("Base class says: " + message)
}

func getMyName() -> String {
return "BaseClass"
}
}

class SubClass: BaseClass {
required init(message: String) {
println("Subclass says: " + message)
super.init(message: message)
}
...
}

і це працює без проблем