Swift 4.2 奇怪的 -.map- 行为

Posted

技术标签:

【中文标题】Swift 4.2 奇怪的 -.map- 行为【英文标题】:Swift 4.2 weird -.map- behavior 【发布时间】:2019-01-13 10:02:35 【问题描述】:

我在 Swift 4.2 的集合上使用 .map 时遇到了一些问题。 这是正在发生的事情:

我有一个这样声明的属性:

var cbPerifList:[CBPeripheral]!

后面在我写代码的时候:

_ = cbPerifList.map  (perif) -> Void in
    print(perif.identifier)

编译器看起来很开心,没有抱怨。

但是当我写的时候:

_ = cbPerifList.map  (perif) -> Void in
    print(perif.identifier)
    print("HELLO")

编译器通过显示此消息来抱怨。

Value of type '[CBPeripheral]' has no member 'identifier'

在代码行上:print(perif.identifier)

有人能解释一下这里发生了什么吗?

    我不明白为什么添加这行代码会有所不同。

    打印(“你好”)

    我希望 perif 是 CBPeripheral 类型,而不是错误消息中所说的 [CBPeripheral]。

【问题讨论】:

你最好在这里使用forEach而不是map 无法在操场上重现(Xcode 10.1),两个代码 sn-ps 都可以工作。另外,如果你只想打印标识符,你应该通过for-inforEach来做,没有理由映射数组。 【参考方案1】:

如其他答案和 cmets 中所述,使用 forEachfor ... in 将是遍历数组的正确方法。

但要回答您的问题并解释为什么那些看似相同的代码 sn-ps 行为不同:这是由几个事实的组合造成的:

[CBPeripheral]! 是一个隐式展开的可选项 (IUO),并且从 Swift 3 开始,如果可能的话,它们被视为常规可选项。比较

SE-0054 Abolish ImplicitlyUnwrappedOptional type Swift 3 incorrect string interpolation with implicitly unwrapped Optionals Implicitly unwrapped optional assign in Xcode 8

Optional 有一个map() 方法:

func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U?

bodies of multi-statement closures don't participate in type inference。

在“单语句”闭包中

_ = cbPerifList.map  (perif) -> Void in
    print(perif.identifier)

编译器尝试从print 表达式推断闭包类型,并且为了对perif.identifier 进行类型检查,必须将IUO cbPerifList 解包到一个数组中。

在“多语句”闭包中

_ = cbPerifList.map  (perif) -> Void in
    print(perif.identifier)
    print("HELLO")

编译器不会尝试从上下文推断闭包类型。因此cbPerifList 被视为常规可选,map() 是上述Optional.map 方法。在闭包内部,perif 具有展开的类型 [CBPeripheral]。这就是为什么perif.identifier 没有编译并显示错误消息的原因

“[CBPeripheral]”类型的值没有成员“标识符”

您可以通过显式类型注释“帮助”编译器

_ = cbPerifList.map  (perif: CBPeripheral) -> Void in
    print(perif.identifier)
    print("HELLO")

但是——如前所述——在这种特殊情况下有更好的解决方案。

【讨论】:

【参考方案2】:

map 在 Swift(和其他地方)中的工作方式是它可以将输入从一种类型映射(更改)到另一种类型。因此,在您的情况下,您将在 [CBPeripheral] 上调用 map 并且对于每个元素,map 函数将返回另一个值。所以,如果identifierString,你会得到一个字符串数组。

它应该是这样工作的。

但是:)

在您的情况下,您已经像这样定义了映射函数

(perif) -> Void

这意味着您将遍历您的数组并调用 map,并使用一个不返回任何内容的函数。这意味着结果将是一个填充了 Void 值的数组。

因此,正如其他人在 cmets 中建议的那样,如果您只想检查 cbPerifList 的内容,最好使用 for in 这样的循环

for cbPerif in cbPerifList 
    print(cbPerif.identifier)

但是,如果您有兴趣获取 CBPeripherals 的名称数组,您可以这样做

let names = cbPerifList.map  $0.identifier 

对上述内容的评论:要了解更多关于我们如何最终只写 $0.name 的信息,请查看 Swift 文档中关于 Closures 的章节,或 this answer

希望对你有所帮助。

【讨论】:

以上是关于Swift 4.2 奇怪的 -.map- 行为的主要内容,如果未能解决你的问题,请参考以下文章

自定义 NSError 奇怪的行为 Swift

Firebase 查询结果 SWIFT 的奇怪行为

使用 objc_getAssociatedObject() 时出现奇怪的 Swift 行为

NSManagedObjectContext 扩展中泛型函数中的奇怪 Swift 行为

使用 Swift 4 和 UIView 的奇怪动画行为

奇怪的行为设置 tableView 行高和 scrollPosition Swift