Phương pháp flatMap(_:)
trên hiện Sequence
(tính Swift 4) có hai ý nghĩa khác nhau:
Có thể mất một transform đóng cửa mà trả về một tùy chọn T?
, và nó sẽ trở lại a [T]
, lọc ra các kết quả nil
(quá tải này is to be renamed đến compactMap(_:)
trong phiên bản sau).
public func flatMap<ElementOfResult>(
_ transform: (Element) throws -> ElementOfResult?
) rethrows -> [ElementOfResult]
Có thể mất một transform đóng cửa mà trả về một Sequence
, và nó sẽ trả về một mảng chứa các nối của tất cả các chuỗi kết quả.
public func flatMap<SegmentOfResult : Sequence>(
_ transform: (Element) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.Element]
Bây giờ, trong Swift 4, String
trở thành một RangeReplaceableCollection
(và do đó một Sequence
).Vì vậy, Swift 3 mã mà đã làm điều này:
// returns ["foo"], as using the `nil` filtering flatMap, the elements in the closure
// are implicitly promoted to optional strings.
["foo"].flatMap { $0 }
nay thực hiện điều này:
// 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 }
Để duy trì khả năng tương thích nguồn, chuyên flatMap
quá tải were added cho chuỗi:
//===----------------------------------------------------------------------===//
// 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)
}
}
như vậy rằng việc sử dụng ở trên vẫn sẽ trả lại một [String]
trong Swift 3 chế độ tương thích, nhưng một [Character]
trong Swift 4.
Vì vậy, tại sao
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)
}
cho bạn biết rằng việc đóng cửa phải trả lại một String?
?
Vâng, Swift hiện không suy ra tham số và trả về các loại cho đóng nhiều câu lệnh (xem this Q&A để biết thêm thông tin). Vì vậy, quá tải flatMap(_:)
khi quá trình đóng trả về hoặc là T?
hoặc chung S : Sequence
không đủ điều kiện để được gọi mà không có chú thích loại rõ ràng, vì chúng sẽ yêu cầu suy luận kiểu để đáp ứng các trình giữ chỗ chung.
Do đó, quá tải duy nhất đủ điều kiện, là khả năng tương thích nguồn đặc biệt String
đặc biệt, vì vậy trình biên dịch dự kiến việc đóng để trả lại String?
.
Để sửa lỗi này, bạn rõ ràng có thể chú thích các kiểu trả về của việc đóng cửa:
array
.flatMap { i -> Int? in
print("DD")
return i
}
.forEach {
print("SS")
print($0)
}
Nhưng nếu bạn không thực sự sử dụng chức năng lọc tùy chọn của flatMap(_:)
quá tải này trong mã thực sự của bạn, bạn nên sử dụng map(_:)
thay thế.
Câu trả lời hay, cảm ơn bạn! Tôi đã sử dụng chức năng lọc tùy chọn của 'flatMap (_ :)' trong mã thực. Tôi vừa xóa một số mã để hiển thị sự cố mà không liên quan chặt chẽ đến các phần vấn đề .. –