#swift #generics #swift-protocols
#swift #общие сведения #swift-протоколы
Вопрос:
Учитывая, что базовые типы одинаковы, я ожидал test2
, что будет true
, не false
:
protocol Foo {}
class Bar: NSObject, Foo {}
class Test {
func testCompare() {
let b = Bar()
let test1 = compare(expected: Bar.self, actual: b)
let c: Foo = b
let test2 = compare(expected: Bar.self, actual: c)
/*
(lldb) p expected
(@thick NSObject.Type) $R0 = SpokestackTests.Bar
(lldb) p type(of: actual).self
(SpokestackTests.Foo.Type) $R2 = SpokestackTests.Bar
*/
print(test1, test2) // true false
}
func compare<T>(expected: NSObject.Type, actual: T) -> Bool {
return expected == type(of: actual).self
}
}
Связано ли это с различием между конкретным метатипом класса и экзистенциальным метатипом экземпляра протокола?
Ответ №1:
После ознакомления с документацией функции type(of:) мы можем перефразировать последний абзац примерно так:
Этот неожиданный результат возникает из-за того, что вызов
type(of: value)
insidecompare(expected:actual:)
должен возвращать метатип, экземпляромT.Type
которого является статический типactual
параметра (Foo.self
) . Чтобы получить динамический тип внутри значения в этом общем контексте, приведите параметр к любому при вызове type(of:) .
или просто измените compare(expected:actual:)
функцию, чтобы использовать Any
type вместо generics:
private func compare(expected: NSObject.Type, actual: Any) -> Bool {
return expected == type(of: actual).self
}
Обновление: еще лучше, вы можете использовать предложение @Jessy в комментариях
func compare<Expected: Foundation.NSObject>(expected: Expected.Type, actual: Any) -> Bool {
return type(of: actual) is Expected.Type
}
Комментарии:
1. Вероятно, лучше выразить как :
func compare<Expected: Foundation.NSObject>( expected _: Expected.Type, actual: Any ) -> Bool { type(of: actual) is Expected.Type }
2. @Jessy да, это, вероятно, лучше. Я обновил свой ответ. Спасибо.
3. Является ли объяснение
type(of:)
поведения, которое, посколькуAny
является как типом значения, так и ссылочным типом (и типом функции!), приведениеactual
типа кAny
позволяет системе типов Swift разрешать разницу между конкретным метатипом класса и экзистенциальным метатипом экземпляра протокола?4. @Noel да. Приведение его как
Any
практически освобождается от общего контекста.
Ответ №2:
Он может сравнивать вашу функцию с тем же объектом сравнения
Он не может сравнивать метатип сравнения с экземпляром, поэтому возвращает false Эти значения также возвращают false, которые вы можете попробовать в pg :
let d: Any = b
_ = compare(expected: Bar.self, actual: d)
d as! Foo
_ = compare(expected: Bar.self, actual: d)