res1對于下面的代碼片段,為什么res2會有不同的值?
func test() {
let a: String? = nil
let b: String? = nil
let foo: (String?) -> Int = { $0 == nil ? 0 : 1}
let res1 = [a, b].compactMap { $0 }.map(foo)
let res2 = [a, b].compactMap { $0 }.map { foo($0) }
print("res1: ", res1)
print("res2: ", res2)
}
輸出是
res1: [0, 0]
res2: []
uj5u.com熱心網友回復:
這似乎是編譯器如何[a, b].compactMap根據下游操作選擇型別的結果。您可以通過檢查引數的型別來查看它們通過函式時的型別:
func printType<T>(_ i: String, _ v: T) -> T {
print(i, "->", T.self)
return v
}
func test() {
let a: String? = nil
let b: String? = nil
let foo: (String?) -> Int = { $0 == nil ? 0 : 1 }
let res1 = printType("cm1", printType("a1", [a, b]).compactMap { $0 }).map(foo)
let res2 = printType("cm2", printType("a2", [a, b]).compactMap { $0 }).map { foo($0) }
print("res1: ", res1)
print("res2: ", res2)
}
test()
// a1 -> Array<Optional<Optional<String>>>
// cm1 -> Array<Optional<String>>
// a2 -> Array<Optional<String>>
// cm2 -> Array<String>
// res1: [0, 0]
// res2: []
看起來:
- 在這種情況下
res1:- 因為
foo需要 aString,map(foo)被鍵入使得 aString?被傳遞 - 并且map要接收 aString?,compactMap必須回傳 a[String?] - 為了
compactMap回傳 a[String?],它的輸入必須是 a[String??] - 雖然
[a, b]默認為 a[String?],但編譯器也可以隱式地將其向上轉換為 a[String??],這就是它的作用 - 因此,僅從 中洗掉了一層可選性
[String??],并且將每個String?值傳遞給mapand intofoo
- 因為
- 在 的情況下
res2,編譯器不受 的嚴格限制map { foo($0) },因為在傳遞給之前可以在閉包內$0隱式向上轉換,這是編譯器更喜歡的:foo$0是一個在String被傳遞給之前被向上轉換的String?foo- 為了
map接收String值,compactMap必須回傳[String] - 由于
compactMap回傳 a[String],它的輸入必須是[String?],[a, b]也就是說,不需要向上轉換 - Hence, now
compactMapis actually filtering thenils out of[String?]into[String], and since no values are left,foois never even called (you can see this with more print statements inside offoo
This sort of thing is very situational in the compiler, and you happened to have found a specific case where this happens. For instance, the compiler parses the results of single-statement closures differently from multi-statement closures: if you turn compactMap { $0 } into compactMap { _ = 1 1; return $0 }, the closure will parsed differently, and type checking will occur in a different order, resulting in [] in both cases:
let res1 = printType("cm1", printType("a1", [a, b]).compactMap { _ = 1 1; return $0 }).map(foo)
let res2 = printType("cm2", printType("a2", [a, b]).compactMap { _ = 1 1; return $0 }).map { foo($0) }
// a1 -> Array<Optional<String>>
// cm1 -> Array<Optional<String>>
// a2 -> Array<Optional<String>>
// cm2 -> Array<Optional<String>>
// res1: [0, 0]
// res2: [0, 0]
In this case, the compiler actually ended up preferring the surprising case in both instances, since return $0 allows the compiler to upcast from String? ? String?? (and then filter back down from [String??] ? [String?])!
Either way, this seems worthy of a report on https://bugs.swift.org, since the behavior is incredibly surprising. I will be happy to add test cases and comments to the report if you go ahead and file.
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/452935.html
標籤:迅速
上一篇:解碼空陣列不拋出指定陣列
