swift 泛型类型方法返回

5tmbdcev  于 2023-03-07  发布在  Swift
关注(0)|答案(1)|浏览(114)

在我的自定义APIClientSwift类中,我定义了一个helper方法,该方法从响应字典中提取给定键的值,检查其类型,并在该值与我想要的类型不对应时抛出错误。
如果允许nil值,只需在方法调用中键入String?.self而不是String.self

static func value<T>(forKey key: String, in dict: [String:Any], type: T.Type) throws -> T? {
    
    let required = !(T.self is ExpressibleByNilLiteral.Type)
    let val = dict[key]
    if val == nil {
        if required {
            throw APIClientResponseError.missing(key: key, in: dict)
        }
        return nil
    }
    if !(val is T) {
        throw APIClientResponseError.invalid(key: key, in: dict)
    }
    return val as? T
}

但是我需要保留T?的返回类型,否则我不能返回nil值。我怎样才能根据类型参数自动输出类型呢?这样当给出可选类型时,它可以输出nil值,当给出必需类型时,它可以输出非nil值。
谢谢!

7d7tgy0s

7d7tgy0s1#

我只想把它写成两个函数,这样就简单多了,调用者仍然可以选择这个值是否是“必需的”,而不是通过传入一个可选类型,而是通过调用适当的函数。

func tryGetValue<T>(forKey key: String, in dict: [String:Any], type: T.Type) -> T? {
    guard let val = dict[key] else {
        return nil
    }
    return val as? T
}

func value<T>(forKey key: String, in dict: [String:Any], type: T.Type) throws -> T {
    guard let val = dict[key] else {
        throw APIClientResponseError.missing(key: key, in: dict)
    }
    guard let t = val as? T else {
        throw APIClientRespondError.invalid(key: key, in: dict)
    }
    return t
}

如果你真的想要一个函数,你可以把“returnnil or throwerror”逻辑抽象成一个协议,尽管说实话,这比我在生产中使用的任何东西都更像是一个黑客。

// Can't really think of a good name for this protocol and its methods...
protocol APIValue {
    static func missing(in dict: [String: Any], key: String) throws -> Self
    static func invalid(in dict: [String: Any], key: String) throws -> Self
}

extension Optional: APIValue {
    static func missing(in dict: [String: Any], key: String) throws -> Optional<Wrapped> {
        nil
    }

    static func invalid(in dict: [String: Any], key: String) throws -> Optional<Wrapped> {
        nil
    }
}

extension APIValue {
    static func missing(in dict: [String: Any], key: String) throws -> Self {
        throw APIClientResponseError.missing(key: key, in: dict)
    }

    static func invalid(in dict: [String: Any], key: String) throws -> Self {
        throw APIClientResponseError.invalid(key: key, in: dict)
    }
}

// add extensions for all the other types that can go in the method...
extension String: APIValue {}
extension Int: APIValue {}
extension Double: APIValue {}
// ...

// now the value method can be:
func value<T: APIValue>(forKey key: String, in dict: [String:Any], type: T.Type) throws -> T {
    guard let val = dict[key] else {
        return try type.missing(dict: dict, key: key)
    }
    guard let t = val as? T else {
        return try type.invalid(dict: dict, key: key)
    }
    return t
}

相关问题