简体   繁体   中英

Why does Swift Array contains(_:) method accept nil argument when it must be non-optional?

I simplified my code as much as I could to make it still be a reproducible example. When I use contains like this in a chain of calls it does compile, work and contains accepts nil when it shouldn't, I think.

let array = [1, 2, 3, 4, 5].filter { _ in
    [1, 2, 3].map { smallNumber in
        "\(smallNumber)"
    }
    .contains(nil)
}

But when I assign map result to a variable and then call contains with nil value the code doesn't even compile.

let array = [1, 2, 3, 4, 5].filter { _ in
    let mappedNumbers = [1, 2, 3].map { smallNumber in
        "\(smallNumber)"
    }
    return mappedNumbers.contains(nil)
}

Xcode is complaining about 'nil' is not compatible with expected argument type 'String' , that is right.

I expect the same error in the first example.

The compiler can automatically wrap a value into an optional, if required by the context. That is what makes simple assignments like

let value: Int? = 123

possible. In your first example, the return type of the closure is inferred as String? from the context, so that the map returns [String?] , and .contains(nil) can be applied to it. Ie the compiler understands the code as

let array = [1, 2, 3, 4, 5].filter { _ in
    [1, 2, 3].map { smallNumber -> String? in
        "\(smallNumber)"
    }
    .contains(nil)
}

In the second example the compiler does not have that context, and mappedNumbers has the type [String] . You can make it compile by specifying the closure return type String? explicitly:

let array = [1, 2, 3, 4, 5].filter { _ in
    let mappedNumbers = [1, 2, 3].map { smallNumber -> String? in
        "\(smallNumber)"
    }
    return mappedNumbers.contains(nil)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM