首页 > 解决方案 > 如何在 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 后,已经看到了这种行为。

任何帮助将不胜感激!

我不希望使用可选返回来制作函数签名,例如

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

因为它是不可扩展的......而且它曾经在没有它的情况下工作。

标签: iosswiftgenericsoverloading

解决方案


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

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

通过as URL在最后添加。


推荐阅读