"Cannot convert return expression" 在 flatMap 中,里面有一个无意义的表达式
"Cannot convert return expression" in flatMap with a meaningless expression inside
我正在检查 .lazy
的高阶函数,发现了一些与 flatMap 函数(可能还有其他函数)相关的有趣的编译错误
例子
让数组 = [1, 2, 3, 4, 5, 6]
大批
.flatMap {
打印("DD")
return $0 // 无法将类型 'Int' 的 return 表达式转换为 return 类型 'String?'
}
.forEach {
打印("SS")
打印($0)
}
注释掉一点
大批
.flatMap {
// 打印("DD")
return $0
}
.forEach {
打印("SS")
打印($0)
}
一切正常..更有趣的例子
大批
.flatMap {
让 z = $0
return $0 // 或者 return z - 都是一样的 "Cannot convert return expression of type 'Int' to return type 'String?'"
}
.forEach {
打印("SS")
打印($0)
}
什么会导致这种行为?
flatMap
根据上下文可以有不同的含义。您可能会更准确地告诉编译器您打算使用哪一个。
将 flatMap
应用于编译器可以推断的数组的两个通常目的是
展平嵌套数组
let array = [[1, 2, 3, 4, 5, 6], [7, 8, 9]]
let flattened = array.flatMap{[=10=]}
print(flattened) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
映射到另一种类型并过滤选项
let array = ["1", "a", "2", "3", "b", "4", "5", "6"]
let flattened = array.flatMap{ Int([=11=]) }
print(flattened) // [1, 2, 3, 4, 5, 6]
目前 Sequence
上的 flatMap(_:)
方法(从 Swift 4 开始)有两种不同的含义:
它可以采用 return 一个可选 T?
的转换闭包,它会 return 一个 [T]
,过滤掉 nil
结果(在未来的版本中将 is to be renamed 重载到 compactMap(_:)
)。
public func flatMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult]
它可以采用一个 return 是一个 Sequence
的转换闭包,它将 return 一个包含所有结果序列串联的数组。
public func flatMap<SegmentOfResult : Sequence>(
_ transform: (Element) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.Element]
现在,在 Swift 4 中,String
变成了 RangeReplaceableCollection
(因此变成了 Sequence
)。所以 Swift 3 个代码执行此操作:
// returns ["foo"], as using the `nil` filtering flatMap, the elements in the closure
// are implicitly promoted to optional strings.
["foo"].flatMap { [=12=] }
现在这样做:
// returns ["f", "o", "o"], a [Character], as using the Sequence concatenation flatMap,
// as String is now a Sequence (compiler favours this overload as it avoids the implicit
// conversion from String to String?)
["foo"].flatMap { [=13=] }
为了保持源兼容性,专门 flatMap
重载 were added 字符串:
//===----------------------------------------------------------------------===//
// The following overloads of flatMap are carefully crafted to allow the code
// like the following:
// ["hello"].flatMap { [=14=] }
// return an array of strings without any type context in Swift 3 mode, at the
// same time allowing the following code snippet to compile:
// [0, 1].flatMap { x in
// if String(x) == "foo" { return "bar" } else { return nil }
// }
// Note that the second overload is declared on a more specific protocol.
// See: test/stdlib/StringFlatMap.swift for tests.
extension Sequence {
@_inlineable // FIXME(sil-serialize-all)
@available(swift, obsoleted: 4)
public func flatMap(
_ transform: (Element) throws -> String
) rethrows -> [String] {
return try map(transform)
}
}
extension Collection {
@_inlineable // FIXME(sil-serialize-all)
public func flatMap(
_ transform: (Element) throws -> String?
) rethrows -> [String] {
return try _flatMap(transform)
}
}
这样上面的用法在 Swift 3 兼容模式下仍然是 return [String]
,但在 Swift 4.
那么,为什么
let array = [1, 2, 3, 4, 5, 6]
array
.flatMap {
print("DD")
return [=15=] // Cannot convert return expression of type 'Int' to return type 'String?'
}
.forEach {
print("SS")
print([=15=])
}
告诉你闭包应该return一个String?
?
好吧,Swift 目前不会为多语句闭包推断参数和 return 类型(有关详细信息,请参阅 this Q&A)。因此 flatMap(_:)
重载,其中闭包 return 是泛型 T?
或泛型 S : Sequence
在没有显式类型注释的情况下不符合调用条件,因为它们需要类型推断以满足通用占位符。
因此,唯一符合条件的重载是特殊的 String
源兼容性重载,因此编译器期望闭包为 return a String?
.
要解决此问题,您可以显式注释闭包的 return 类型:
array
.flatMap { i -> Int? in
print("DD")
return i
}
.forEach {
print("SS")
print([=16=])
}
但是,如果您实际上并未在实际代码中使用此 flatMap(_:)
重载的可选过滤功能,则应改用 map(_:)
。
我正在检查 .lazy
的高阶函数,发现了一些与 flatMap 函数(可能还有其他函数)相关的有趣的编译错误
例子
让数组 = [1, 2, 3, 4, 5, 6] 大批 .flatMap { 打印("DD") return $0 // 无法将类型 'Int' 的 return 表达式转换为 return 类型 'String?' } .forEach { 打印("SS") 打印($0) }
注释掉一点
大批 .flatMap { // 打印("DD") return $0 } .forEach { 打印("SS") 打印($0) }
一切正常..更有趣的例子
大批 .flatMap { 让 z = $0 return $0 // 或者 return z - 都是一样的 "Cannot convert return expression of type 'Int' to return type 'String?'" } .forEach { 打印("SS") 打印($0) }
什么会导致这种行为?
flatMap
根据上下文可以有不同的含义。您可能会更准确地告诉编译器您打算使用哪一个。
将 flatMap
应用于编译器可以推断的数组的两个通常目的是
展平嵌套数组
let array = [[1, 2, 3, 4, 5, 6], [7, 8, 9]] let flattened = array.flatMap{[=10=]} print(flattened) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
映射到另一种类型并过滤选项
let array = ["1", "a", "2", "3", "b", "4", "5", "6"] let flattened = array.flatMap{ Int([=11=]) } print(flattened) // [1, 2, 3, 4, 5, 6]
目前 Sequence
上的 flatMap(_:)
方法(从 Swift 4 开始)有两种不同的含义:
它可以采用 return 一个可选
T?
的转换闭包,它会 return 一个[T]
,过滤掉nil
结果(在未来的版本中将 is to be renamed 重载到compactMap(_:)
)。public func flatMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult? ) rethrows -> [ElementOfResult]
它可以采用一个 return 是一个
Sequence
的转换闭包,它将 return 一个包含所有结果序列串联的数组。public func flatMap<SegmentOfResult : Sequence>( _ transform: (Element) throws -> SegmentOfResult ) rethrows -> [SegmentOfResult.Element]
现在,在 Swift 4 中,String
变成了 RangeReplaceableCollection
(因此变成了 Sequence
)。所以 Swift 3 个代码执行此操作:
// returns ["foo"], as using the `nil` filtering flatMap, the elements in the closure
// are implicitly promoted to optional strings.
["foo"].flatMap { [=12=] }
现在这样做:
// returns ["f", "o", "o"], a [Character], as using the Sequence concatenation flatMap,
// as String is now a Sequence (compiler favours this overload as it avoids the implicit
// conversion from String to String?)
["foo"].flatMap { [=13=] }
为了保持源兼容性,专门 flatMap
重载 were added 字符串:
//===----------------------------------------------------------------------===// // The following overloads of flatMap are carefully crafted to allow the code // like the following: // ["hello"].flatMap { [=14=] } // return an array of strings without any type context in Swift 3 mode, at the // same time allowing the following code snippet to compile: // [0, 1].flatMap { x in // if String(x) == "foo" { return "bar" } else { return nil } // } // Note that the second overload is declared on a more specific protocol. // See: test/stdlib/StringFlatMap.swift for tests. extension Sequence { @_inlineable // FIXME(sil-serialize-all) @available(swift, obsoleted: 4) public func flatMap( _ transform: (Element) throws -> String ) rethrows -> [String] { return try map(transform) } } extension Collection { @_inlineable // FIXME(sil-serialize-all) public func flatMap( _ transform: (Element) throws -> String? ) rethrows -> [String] { return try _flatMap(transform) } }
这样上面的用法在 Swift 3 兼容模式下仍然是 return [String]
,但在 Swift 4.
那么,为什么
let array = [1, 2, 3, 4, 5, 6]
array
.flatMap {
print("DD")
return [=15=] // Cannot convert return expression of type 'Int' to return type 'String?'
}
.forEach {
print("SS")
print([=15=])
}
告诉你闭包应该return一个String?
?
好吧,Swift 目前不会为多语句闭包推断参数和 return 类型(有关详细信息,请参阅 this Q&A)。因此 flatMap(_:)
重载,其中闭包 return 是泛型 T?
或泛型 S : Sequence
在没有显式类型注释的情况下不符合调用条件,因为它们需要类型推断以满足通用占位符。
因此,唯一符合条件的重载是特殊的 String
源兼容性重载,因此编译器期望闭包为 return a String?
.
要解决此问题,您可以显式注释闭包的 return 类型:
array
.flatMap { i -> Int? in
print("DD")
return i
}
.forEach {
print("SS")
print([=16=])
}
但是,如果您实际上并未在实际代码中使用此 flatMap(_:)
重载的可选过滤功能,则应改用 map(_:)
。