swift - 为什么将 A<B> 转换为 A<C> 有时会成功,即使 B 和 C 无关?

标签 swift macos generics

我正在使用 Contacts 框架,我有循环遍历 CNContact 的所有值的代码,并执行以下操作:

if let label = value as? CNLabeledValue<CNPhoneNumber> {
    let v: CNPhoneNumber = label.value
    NSLog("v = \(v), type = \(type(of: v))")
}

大多数情况下,它会像这样打印输出:

v = <CNPhoneNumber: 0x1234567890a0: countryCode=us, digits=7775551212>, type = CNPhoneNumber

但它也会像这样打印输出:

v = foo@example.com, type = __NSCFString

不过,在我尝试过的其他情况下,占位符类型作为类型的一部分是相关的:

Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
  1> class C<T> { }
  2> let c1 = C<Int>()
c1: C<Int> = {}
  3> let c2 = C<String>()
c2: C<String> = {}
  4> c1 as? C<String>
$R0: C<String>? = nil

这里的规则是什么?为什么 CNLabeledValue<NSString> 在这里成功转换为 CNLabeledValue<CNPhoneNumber>?那么如何准确检测这种类型呢?

编辑:这是一个完整的程序:

import Cocoa
import Contacts
let me = try! CNContactStore().unifiedMeContactWithKeys(toFetch: [CNContactEmailAddressesKey as NSString])
let value = me.value(forKey: CNContactEmailAddressesKey)
if let array = value as? [CNLabeledValue<CNPhoneNumber>] {
    for item in array {
        if let phone = item as? CNLabeledValue<CNPhoneNumber> {
            let v: CNPhoneNumber = phone.value
            NSLog("v = \(v), type = \(type(of: v))")
        }
    }
}

最佳答案

CNLabeledValue 是一个 Objective-C 类。 Objective-C 没有真正的泛型。当 Swift 出现时,引入了所谓的“轻量级泛型”以提高与 Swift 的互操作性。这些只会帮助编译器进行类型检查,但在运行时会丢失额外的类型信息(基本上是 type erasure )。这就是为什么您在第一个示例中得到任何类型的原因。

在您的第二个示例中,您定义了真正的 Swift 泛型。那里的类​​型不会被删除,因此它们在运行时可用,并且可以实际检查类型。

关于swift - 为什么将 A<B> 转换为 A<C> 有时会成功,即使 B 和 C 无关?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41880826/

相关文章:

ios - 我触摸 iAd,Xcode 识别出我也触摸了背景

macos - 为什么使用 "mate"命令打开 TextMate 标题栏时不显示文件路径?

php - 如何在 macOS Catalina 上使用brew 安装适用于 PHP 7.4 的 memcached 3.1.4?

oop - Kotlin 类型推断失败的原因

c# - 自动映射器的通用扩展方法

java - 将 fragment 作为参数传递?

swift - @State 变量的值不会改变

ios - 显示更多不同位置的障碍物 - Swift

swift - 调整 NSVisualEffectView 模糊半径和透明度

ios - Swift struct array into Dictionary 抛出一个 nil 值