未调用最具体的通用函数
Most specific generic function not called
我正在使用 @propertyWrapper
来减少我的 UserDefaults
样板,如下所示……
enum PreferenceKey: String, CaseIterable {
case enumName, stringName
}
@propertyWrapper
struct Prefs<T> {
let key: PreferenceKey
var wrappedValue: T? {
get {
UserDefaults.object(for: key)
}
set {
UserDefaults.set(newValue, for: key)
}
}
}
struct Preferences {
@Prefs(key: .enumName) static var enumName: Name?
@Prefs(key: .stringName) static var stringName: String?
}
extension UserDefaults {
static func object<T>(for key: PreferenceKey) -> T? {
standard.object(forKey: key.rawValue) as? T
}
static func object<T: RawRepresentable>(for key: PreferenceKey) -> T? where T.RawValue == String {
if let value = standard.object(forKey: key.rawValue) as? String {
return T(rawValue: value)
}
return nil
}
static func set<T: RawRepresentable>(_ value: T, for key: PreferenceKey) {
print("Set Raw Value \(value)")
standard.set(value.rawValue, forKey: key.rawValue)
}
static func set<T>(_ value: T, for key: PreferenceKey) {
print("Set Value \(value)")
standard.set(value, forKey: key.rawValue)
}
}
这在设置常规 属性 列表类型时效果很好…
Preferences.stringName = "Fred"
// Set Value Optional("Fred")
print(Preferences.stringName)
// Optional("Fred")
但是当试图设置一个 RawRepresentable
的值时,它失败了……
Preferences.enumName = .Fred
// Set Value Optional(__lldb_expr_10.Name.Fred)
// libc++abi.dylib: terminating with uncaught exception of type NSException
它调用非特定版本,而不是调用 UserDefaults.set(
的最具体版本。
刚打电话
UserDefaults.set(Name.Fred, for: .enumName)
工作正常。在这种情况下,它会调用最具体的函数。
经过进一步测试,这似乎不是 @propertyWrapper
问题。以下顶级函数也无法调用更具体的通用函数。似乎某些类型信息在某处丢失
func set<T>(_ value: T?) {
UserDefaults.set(value, for: .enumName)
}
set(Name.Fred)
// Set Value Optional(__lldb_expr_5.Name.Fred)
// libc++abi.dylib: terminating with uncaught exception of type NSException
我错过了什么?关于如何解决这个问题有什么想法吗?
What am I missing?
Swift 本质上是一种静态类型语言,select调用哪个函数重载是在编译时确定的。
在您的工作示例中:
UserDefaults.set(Name.Fred, for: .enumName)
编译器知道第一个参数的类型。此类型实现 RawRepresentable
并且编译器使用它来 select 您期望的重载。
现在考虑你失败的例子:
func set<T>(_ value: T?) {
UserDefaults.set(value, for: .enumName)
}
set(Name.Fred)
当编译器编译 set
函数时 它唯一知道参数 value
的是它有一个可以引用的类型T
。 T
没有约束,在运行时可以传递任何类型的值,所以在确定UserDefaults.set
的哪个重载编译调用编译器只能 select 也没有约束并接受任何类型的值的重载。
Any thoughts as to how I can resolve this?
您已经知道一种解决方案,您重载了 UserDefaults.set
,您可以重载您的 set
函数。但是,您可能希望根据 Swift 的重载编译时解析来考虑您的设计——您可能不希望重载函数层相互调用。
HTH
我正在使用 @propertyWrapper
来减少我的 UserDefaults
样板,如下所示……
enum PreferenceKey: String, CaseIterable {
case enumName, stringName
}
@propertyWrapper
struct Prefs<T> {
let key: PreferenceKey
var wrappedValue: T? {
get {
UserDefaults.object(for: key)
}
set {
UserDefaults.set(newValue, for: key)
}
}
}
struct Preferences {
@Prefs(key: .enumName) static var enumName: Name?
@Prefs(key: .stringName) static var stringName: String?
}
extension UserDefaults {
static func object<T>(for key: PreferenceKey) -> T? {
standard.object(forKey: key.rawValue) as? T
}
static func object<T: RawRepresentable>(for key: PreferenceKey) -> T? where T.RawValue == String {
if let value = standard.object(forKey: key.rawValue) as? String {
return T(rawValue: value)
}
return nil
}
static func set<T: RawRepresentable>(_ value: T, for key: PreferenceKey) {
print("Set Raw Value \(value)")
standard.set(value.rawValue, forKey: key.rawValue)
}
static func set<T>(_ value: T, for key: PreferenceKey) {
print("Set Value \(value)")
standard.set(value, forKey: key.rawValue)
}
}
这在设置常规 属性 列表类型时效果很好…
Preferences.stringName = "Fred"
// Set Value Optional("Fred")
print(Preferences.stringName)
// Optional("Fred")
但是当试图设置一个 RawRepresentable
的值时,它失败了……
Preferences.enumName = .Fred
// Set Value Optional(__lldb_expr_10.Name.Fred)
// libc++abi.dylib: terminating with uncaught exception of type NSException
它调用非特定版本,而不是调用 UserDefaults.set(
的最具体版本。
刚打电话
UserDefaults.set(Name.Fred, for: .enumName)
工作正常。在这种情况下,它会调用最具体的函数。
经过进一步测试,这似乎不是 @propertyWrapper
问题。以下顶级函数也无法调用更具体的通用函数。似乎某些类型信息在某处丢失
func set<T>(_ value: T?) {
UserDefaults.set(value, for: .enumName)
}
set(Name.Fred)
// Set Value Optional(__lldb_expr_5.Name.Fred)
// libc++abi.dylib: terminating with uncaught exception of type NSException
我错过了什么?关于如何解决这个问题有什么想法吗?
What am I missing?
Swift 本质上是一种静态类型语言,select调用哪个函数重载是在编译时确定的。
在您的工作示例中:
UserDefaults.set(Name.Fred, for: .enumName)
编译器知道第一个参数的类型。此类型实现 RawRepresentable
并且编译器使用它来 select 您期望的重载。
现在考虑你失败的例子:
func set<T>(_ value: T?) { UserDefaults.set(value, for: .enumName) } set(Name.Fred)
当编译器编译 set
函数时 它唯一知道参数 value
的是它有一个可以引用的类型T
。 T
没有约束,在运行时可以传递任何类型的值,所以在确定UserDefaults.set
的哪个重载编译调用编译器只能 select 也没有约束并接受任何类型的值的重载。
Any thoughts as to how I can resolve this?
您已经知道一种解决方案,您重载了 UserDefaults.set
,您可以重载您的 set
函数。但是,您可能希望根据 Swift 的重载编译时解析来考虑您的设计——您可能不希望重载函数层相互调用。
HTH