在flatMap中“无法转换返回表达式”,其中包含无意义的表达式

时间:2017-12-25 11:51:09

标签: arrays swift flatmap

我正在检查.lazy的高阶函数,并且得到了一些与flatMap函数相关的有趣编译错误(可能还有其他函数)

实施例

 
let array = [1, 2, 3, 4, 5, 6]

array
    .flatMap {
        print("DD")
        return $0 // Cannot convert return expression of type 'Int' to return type 'String?'
    }
    .forEach {
        print("SS")
        print($0)
}

评论一下

 
array
    .flatMap {
//        print("DD")
        return $0
    }
    .forEach {
        print("SS")
        print($0)
}

一切正常......更有趣的例子

 
array
    .flatMap {
        let z = $0
        return $0  // Or return z - all is the same "Cannot convert return expression of type 'Int' to return type 'String?'"
    }
    .forEach {
        print("SS")
        print($0)
}

什么可能导致这种行为?

2 个答案:

答案 0 :(得分:4)

flatMap根据具体情况可能有不同的含义。您可以更准确地告诉编译器您打算使用哪一个。

enter image description here

flatMap应用于编译器可以推断的数组的两个通常目的是

  • 展平嵌套数组

    let array = [[1, 2, 3, 4, 5, 6], [7, 8, 9]]
    let flattened = array.flatMap{$0}
    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($0) }
    print(flattened) // [1, 2, 3, 4, 5, 6]
    

答案 1 :(得分:4)

目前flatMap(_:)上的Sequence方法(截至Swift 4)有两种不同的含义:

  • 可以采用返回可选T?的转换闭包,它将返回[T],过滤掉nil结果(此重载is to be renamed }在未来的版本中。

    compactMap(_:)

  • 可以采用返回public func flatMap<ElementOfResult>( _ transform: (Element) throws -> ElementOfResult? ) rethrows -> [ElementOfResult]的转换闭包,它将返回一个包含所有结果序列串联的数组。

    Sequence

现在,在Swift 4中,public func flatMap<SegmentOfResult : Sequence>( _ transform: (Element) throws -> SegmentOfResult ) rethrows -> [SegmentOfResult.Element]成为String(因此成为RangeReplaceableCollection)。所以Swift 3代码做到了这一点:

Sequence

现在这样做:

// returns ["foo"], as using the `nil` filtering flatMap, the elements in the closure
// are implicitly promoted to optional strings.
["foo"].flatMap { $0 }

为了保持源兼容性,针对字符串的专门// 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 { $0 } 重载were added

flatMap

这样上述用法仍然会在Swift 3兼容模式下返回//===----------------------------------------------------------------------===// // The following overloads of flatMap are carefully crafted to allow the code // like the following: // ["hello"].flatMap { $0 } // 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 4中返回[String]

那么,为什么

[Character]

告诉你闭包应该返回let array = [1, 2, 3, 4, 5, 6] array .flatMap { print("DD") return $0 // Cannot convert return expression of type 'Int' to return type 'String?' } .forEach { print("SS") print($0) }

好吧,Swift目前不会推断多语句闭包的参数和返回类型(有关详细信息,请参阅this Q&A)。因此,如果没有显式类型注释,则闭包返回泛型String?或泛型flatMap(_:)的{​​{1}}重载不符合要求,因为它们需要类型推断来满足泛型占位符。

因此,唯一符合条件的重载是特殊的T?源兼容性,因此编译器期望闭包返回S : Sequence

要解决此问题,您可以显式注释闭包的返回类型:

String

但是,如果您实际上没有在实际代码中使用此String?重载的可选过滤功能,则应使用array .flatMap { i -> Int? in print("DD") return i } .forEach { print("SS") print($0) } 代替。