compactMap 在存储在可选变量中时表现不同
compactMap behaves differently when storing in an optional variable
考虑以下数组。
let marks = ["86", "45", "thiry six", "76"]
我在以下两个案例中解释了我的疑惑。
案例#1
// Compact map without optionals
let compactMapped: [Int] = marks.compactMap { Int([=11=]) }
print("\(compactMapped)")
结果 - [86, 45, 76]
案例#2
// Compact map with optionals
let compactMappedOptional: [Int?] = marks.compactMap { Int([=12=]) }
print("\(compactMappedOptional)")
结果 - [可选(86),可选(45),无,可选(76)]
为什么Case#2的结果是“nil”?谁能解释为什么案例#2 中的 [Optional(86), Optional(45), Optional(76)] 不是这样的? (PFA 游乐场)
我将此行为作为 bug at bugs.swift.org 提交,结果返回时“按预期工作”。为了找到一种向您解释的方法,我不得不对答复进行一些思考;我认为这非常准确和清楚地重新表达了它。我们开始了!
为了看看这里发生了什么,让我们自己写一些类似 compactMap
的东西。假设 compactMap
做了三件事:
通过给定的transform映射原始数组,期望产生Optionals;在此特定示例中,它生成 Int?
个元素。
过滤掉 nils。
强制解包 Optionals(安全,因为现在没有 nils)。
所以这是“正常”行为,分解为这种理解方式:
let marks = ["86", "45", "thiry six", "76"]
let result = marks.map { element -> Int? in
return Int(element)
}.filter { element in
return element != nil
}.map { element in
return element!
}
好的,但是在你的例子中,转换为 [Int?]
告诉 compactMap
输出 Int?
,这意味着它的第一个 map
必须产生 Int??
.
let result3 = marks.map { element -> Int?? in
return Int(element) // wrapped in extra Optional!
}.filter { element in
return element != nil
}.map { element in
return element!
}
所以第一个map
产生双重包装的Optionals,即Optional(Optional(86))
、Optional(Optional(45))
、Optional(nil)
、Optional(Optional(76))
.
None 个是 nil
,所以它们都通过过滤器,然后它们都被展开一次以给出您要打印的结果。
回复我的报告的 Swift 专家承认这有一些违反直觉的地方,但这是我们为分配给 Optional 执行自动包装的自动行为付出的代价。换句话说,你可以说
let i : Int? = 1
因为 1
在你进入作业的过程中被包裹在一个 Optional 中。您的 [Int?]
演员要求完全相同的行为。
解决方法是自己明确指定转换的输出类型:
let result3 = marks.compactMap {element -> Int? in Int(element) }
这会阻止编译器自己得出关于 map 函数的输出类型应该是什么的结论。问题已解决。
[您可能还想查看 Swift 中关于类型推断的 WWDC 2020 video。]
考虑以下数组。
let marks = ["86", "45", "thiry six", "76"]
我在以下两个案例中解释了我的疑惑。
案例#1
// Compact map without optionals
let compactMapped: [Int] = marks.compactMap { Int([=11=]) }
print("\(compactMapped)")
结果 - [86, 45, 76]
案例#2
// Compact map with optionals
let compactMappedOptional: [Int?] = marks.compactMap { Int([=12=]) }
print("\(compactMappedOptional)")
结果 - [可选(86),可选(45),无,可选(76)]
为什么Case#2的结果是“nil”?谁能解释为什么案例#2 中的 [Optional(86), Optional(45), Optional(76)] 不是这样的? (PFA 游乐场)
我将此行为作为 bug at bugs.swift.org 提交,结果返回时“按预期工作”。为了找到一种向您解释的方法,我不得不对答复进行一些思考;我认为这非常准确和清楚地重新表达了它。我们开始了!
为了看看这里发生了什么,让我们自己写一些类似 compactMap
的东西。假设 compactMap
做了三件事:
通过给定的transform映射原始数组,期望产生Optionals;在此特定示例中,它生成
Int?
个元素。过滤掉 nils。
强制解包 Optionals(安全,因为现在没有 nils)。
所以这是“正常”行为,分解为这种理解方式:
let marks = ["86", "45", "thiry six", "76"]
let result = marks.map { element -> Int? in
return Int(element)
}.filter { element in
return element != nil
}.map { element in
return element!
}
好的,但是在你的例子中,转换为 [Int?]
告诉 compactMap
输出 Int?
,这意味着它的第一个 map
必须产生 Int??
.
let result3 = marks.map { element -> Int?? in
return Int(element) // wrapped in extra Optional!
}.filter { element in
return element != nil
}.map { element in
return element!
}
所以第一个map
产生双重包装的Optionals,即Optional(Optional(86))
、Optional(Optional(45))
、Optional(nil)
、Optional(Optional(76))
.
None 个是 nil
,所以它们都通过过滤器,然后它们都被展开一次以给出您要打印的结果。
回复我的报告的 Swift 专家承认这有一些违反直觉的地方,但这是我们为分配给 Optional 执行自动包装的自动行为付出的代价。换句话说,你可以说
let i : Int? = 1
因为 1
在你进入作业的过程中被包裹在一个 Optional 中。您的 [Int?]
演员要求完全相同的行为。
解决方法是自己明确指定转换的输出类型:
let result3 = marks.compactMap {element -> Int? in Int(element) }
这会阻止编译器自己得出关于 map 函数的输出类型应该是什么的结论。问题已解决。
[您可能还想查看 Swift 中关于类型推断的 WWDC 2020 video。]