如何在 Swift 5.1 (Xcode 11 Playground) 中为可选项实现泛型和非泛型函数签名的重载?

How can I achieve overloading both generic and non-generic function signatures for optionals in Swift 5.1 (Xcode 11 Playground)?

import Foundation

enum Errors: Error {
    case badParse
}

public typealias JSONDictionary = [String: Any]

public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL {

    guard let string = dictionary[key] as? String else {
        throw Errors.badParse
    }

    if let url = URL(string: string) {
        return url
    }

    throw Errors.badParse
}

public func decode<T>(_ dictionary: JSONDictionary, key: String) throws -> T {

    guard let value = dictionary[key] else {
        throw Errors.badParse
    }

    guard let attribute = value as? T else {
        throw Errors.badParse
    }

    return attribute
}

let url: URL = try decode(["url":"test/url"], key: "url") // url: test/url
let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") // nil

只要您正在解码一个非可选的,上面的代码就可以工作。调用特定的非通用解码函数并构造 URL 。

但是,如果您有一个可选类型的变量并对它进行解码,它将不会使用正确的函数。在 swift 4.2 中,可选项和非可选项都将使用正确的非泛型函数,但自从我更新到 Xcode 11 swift 5.1 后,已经看到了这种行为。

如有任何帮助,我们将不胜感激!

我不想使用可选的 returns 来制作函数签名,例如

public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL? {

因为它不可扩展...而且过去没有它也能正常工作。

显然,类型推断的工作方式在 Swift 5 中发生了一些变化。如果您只是想让它使用正确的重载,您只需要给它一点推动:

let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") as URL

通过在末尾添加 as URL