“歧义使用”和受约束的通用功能

时间:2019-12-12 04:03:01

标签: swift

我有一组从字典中提取值的函数,其中字典的值类型为Any(它来自JSON数据,我无法控制值的类型):

func get<T>(_ dict: [String: Any], key: String) throws -> T {
    // cast the value for the key to a T, and return
}

func get<T: RawRepresentable>(_ dict: [String: Any], key: String) throws -> T {
    // cast the value for the key to a T.RawValue, init a T, and return
}

这很好。第一个函数可以转换标量类型的值并将其返回,而第二个函数可以将enum类型的原始值转换为更高级别的Swift类型。

如果添加第三个变体,则编译器会感到不满意,并且会得到很多“模棱两可”的错误,将所有三个功能标记为候选:

func get<T: RawRepresentable>(_ dict: [String: Any], key: String) throws -> T where T.RawValue == Double {
    // try to extract the value as an Double, init a T, and return
    // if that fails, extract as an Int, cast to a Double, init a T, and return
}

使用此功能的想法是,双精度值可能不带小数出现,并且实际上是字典中的Int,但在强类型的Swift-land中它必须是Double

为什么编译器能够在没有第三种变体的情况下解决歧义,却将所有这三种变量都视为同等有效的候选者?

编辑:这是一个说明问题的操场。

enum E: Error {
    case error
}

func get<T>(_ dict: [String: Any], key: String) throws -> T {
    guard let value = dict[key] as? T else { throw E.error }
    return value
}

func get<T: RawRepresentable>(_ dict: [String: Any], key: String) throws -> T {
    guard let rawValue = dict[key] as? T.RawValue else { throw E.error }
    return T(rawValue: rawValue)!
}

func get<T: RawRepresentable>(_ dict: [String: Any], key: String) throws -> T where T.RawValue == Double {
    if let doubleValue = dict[key] as? Double {
        return T(rawValue: doubleValue)!
    } else if let intValue = dict[key] as? Int {
        return T(rawValue: Double(intValue))!
    }

    throw E.error
}

struct Wrapped: RawRepresentable {
    typealias RawValue = Double

    var rawValue: Double

    init?(rawValue: Double) {
        self.rawValue = rawValue
    }
}

let dict: [String: Any] = ["int": 1, "double": 1.1]
let int: Int = try! get(dict, key: "int")
let double: Double = try! get(dict, key: "double")
let wrapped: Wrapped = try! get(dict, key: "int")

这会产生编译错误(模糊使用get(_:key:))。注释掉get<T>的第三种专业化可解决编译器错误,但会导致运行时错误,因为无法使用int将键as?的整数值转换为{{1 }}。将密钥更改为Double可以解决此问题,但不能解决我试图解决的问题。

我应该注意,这对我来说是一个学术问题,因为我已经更改了解析方法以使用double,并且它可以将浮点和整数值解析为Codable / {{ 1}}类型的Swift。

0 个答案:

没有答案