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-in
或forEach
来做,没有理由映射数组。
【参考方案1】:
如其他答案和 cmets 中所述,使用 forEach
或 for ... in
将是遍历数组的正确方法。
但要回答您的问题并解释为什么那些看似相同的代码 sn-ps 行为不同:这是由几个事实的组合造成的:
[CBPeripheral]!
是一个隐式展开的可选项 (IUO),并且从 Swift 3 开始,如果可能的话,它们被视为常规可选项。比较
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
函数将返回另一个值。所以,如果identifier
是String
,你会得到一个字符串数组。
它应该是这样工作的。
但是:)
在您的情况下,您已经像这样定义了映射函数
(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- 行为的主要内容,如果未能解决你的问题,请参考以下文章
使用 objc_getAssociatedObject() 时出现奇怪的 Swift 行为