Swift 如何在初始值设定项中获得受约束泛型的动态分派

Swift 如何在初始值设定项中获得受约束泛型的动态分派,swift,generics,initializer,dynamic-dispatch,Swift,Generics,Initializer,Dynamic Dispatch,下面的代码工作正常: protocol VariableType { associatedtype T var value : T { get } } class UserDefaultsVariable<T> : VariableType { let storageKey : String var value : T { get { return U

下面的代码工作正常:

protocol VariableType {
    
    associatedtype T
    
    var value : T { get }
 
}

class UserDefaultsVariable<T> : VariableType {
   
    let storageKey : String
    
    var value : T {
        
        get {
            return UserDefaults.standard.object(forKey: storageKey) as! T
        }
        
        set(value) {
            UserDefaults.standard.set(value, forKey: storageKey)
        }
    }
    
    init( storageKey : String, initialValue : T  ) {
        self.storageKey = storageKey
        // I want dynamic dispatch here so that if T: RawRepresentable then the
        // function in the extension is called
        self.registerDefaultValue(initialValue: initialValue)
    }
    
    func registerDefaultValue( initialValue : T ) {
        debugPrint("this is called both times!")
        UserDefaults.standard.register(defaults: [storageKey : initialValue])
    }
    
}
当我称之为:

let simpleDefault = UserDefaultsVariable<Int>(storageKey: "simple", initialValue: 0)
let initialValue = simpleDefault.value

enum Direction : Int {
    case left = 0
    case right = 1
}

let enumedDefault = UserDefaultsVariable<Direction>(storageKey: "enumed", initialValue: .left)
这将很好地编译,并从超类中的初始值设定项调用子类中的
registerDefaultValue


我真的很感谢你的帮助。

我认为你在概念上遇到的问题是,事实上,这个故事中没有“动态调度”。动态分派是一种涉及多态性的运行时机制,您的代码不包含多态性。泛型完全在编译时解析:将要发生的事情显式地写入代码中

要了解我的意思,只需执行以下操作:将所有
UserDefaultsVariable(…)
更改为
UserDefaultsVariable.init(…)
,以给自己一些可以单击的内容,然后启动Control命令单击术语。您将看到我们从何处跳到编译器如何路由每个调用


enumedDefault
显式键入为
UserDefaultsVariable
。你就是这样打的。所以我们(皇家编译器“我们”)知道调用什么
registerDefaultValue
。没有“派遣”。但是没有(也不可能)为RAW可表示扩展定义任何特殊指定的
init
,而
self
只是
self
在初始值设定项中。因此,初始值设定项不会基于某种运行时测试(泛型参数化类型是否符合RawRepresentable)神奇地调用另一个
registerDefaultValue

我认为您遇到的概念性问题是,事实上,在这个故事中没有“动态调度”。动态分派是一种涉及多态性的运行时机制,您的代码不包含多态性。泛型完全在编译时解析:将要发生的事情显式地写入代码中

要了解我的意思,只需执行以下操作:将所有
UserDefaultsVariable(…)
更改为
UserDefaultsVariable.init(…)
,以给自己一些可以单击的内容,然后启动Control命令单击术语。您将看到我们从何处跳到编译器如何路由每个调用


enumedDefault
显式键入为
UserDefaultsVariable
。你就是这样打的。所以我们(皇家编译器“我们”)知道调用什么
registerDefaultValue
。没有“派遣”。但是没有(也不可能)为RAW可表示扩展定义任何特殊指定的
init
,而
self
只是
self
在初始值设定项中。因此,初始值设定项不会基于某种运行时测试(泛型参数化类型是否符合RawRepresentable)神奇地调用另一个
registerDefaultValue

这里是一种可能的方法

这样做的目的是使初始值设定项在扩展中更加方便,从而使泛型专用扩展与默认扩展重叠

测试并使用Xcode 11.4/swift 5.2

class UserDefaultsVariable<T> : VariableType {

    let storageKey : String

    init(storageKey: String) {
        self.storageKey = storageKey
    }

    var value : T {

        get {
            return UserDefaults.standard.object(forKey: storageKey) as! T
        }

        set(value) {
            UserDefaults.standard.set(value, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey : initialValue])
    }

}

extension UserDefaultsVariable {

    // this initializer uses default T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }
}

extension UserDefaultsVariable where T: RawRepresentable {

    // this initializer uses specialised T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }

    var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}
class UserDefaultsVariable:VariableType{
让storageKey:字符串
init(storageKey:String){
self.storageKey=storageKey
}
var值:T{
得到{
将UserDefaults.standard.object(forKey:storageKey)返回为!T
}
设置(值){
UserDefaults.standard.set(值,forKey:storageKey)
}
}
func registerDefaultValue(初始值:T){
UserDefaults.standard.register(默认值:[storageKey:initialValue])
}
}
扩展UserDefaultsVariable{
//此初始值设定项使用默认的T
便利初始化(storageKey:String,initialValue:T){
self.init(storageKey:storageKey)
self.registerDefaultValue(initialValue:initialValue)
}
}
扩展UserDefaultsVariable,其中T:RawRepresentable{
//此初始值设定项使用专门的T
便利初始化(storageKey:String,initialValue:T){
self.init(storageKey:storageKey)
self.registerDefaultValue(initialValue:initialValue)
}
var值:T{
得到{
将rawValue=UserDefaults.standard.object(forKey:storageKey)设为!T.rawValue
返回T(原始值:原始值)!
}
设置{
UserDefaults.standard.set(newValue.rawValue,forKey:storageKey)
}
}
func registerDefaultValue(初始值:T){
UserDefaults.standard.register(默认值:[storageKey:initialValue.rawValue])
}
}

这里是可能的方法

这样做的目的是使初始值设定项在扩展中更加方便,从而使泛型专用扩展与默认扩展重叠

测试并使用Xcode 11.4/swift 5.2

class UserDefaultsVariable<T> : VariableType {

    let storageKey : String

    init(storageKey: String) {
        self.storageKey = storageKey
    }

    var value : T {

        get {
            return UserDefaults.standard.object(forKey: storageKey) as! T
        }

        set(value) {
            UserDefaults.standard.set(value, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey : initialValue])
    }

}

extension UserDefaultsVariable {

    // this initializer uses default T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }
}

extension UserDefaultsVariable where T: RawRepresentable {

    // this initializer uses specialised T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }

    var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}
class UserDefaultsVariable:VariableType{
让storageKey:字符串
init(storageKey:String){
self.storageKey=storageKey
}
var值:T{
得到{
将UserDefaults.standard.object(forKey:storageKey)返回为!T
}
设置(值){
UserDefaults.standard.set(值,forKey:storageKey)
}
}
func registerDefaultValue(初始值:T){
UserDefaults.standard.register(默认值:[storageKey:initialValue])
}
}
扩展UserDefaultsVariable{
//此初始值设定项使用默认的T
便利初始化(storageKey:String,initialValue:T){
self.init(storageKey:storageKey)
self.registerDefaultValue(initialValue:initialValue)
}
}
扩展UserDefaultsVariable,其中T:RawRepresentable{
//此初始值设定项使用专门的T
便利初始化(storageKey:String,initialValue:T){
self.init(storageKey:storageKey)
self.registerDefaultValue(initialValue:initialValue)
}
var值:T{
得到{
将rawValue=UserDefaults.standard.object(forKey:storageKey)设为!T.rawValue
返回T(原始值:原始值)!
}
设置{
UserDefaults.standard.set(newValue.rawValue,forKey:storageKey)
class RawRepresentableUserDefaultsVariable<T: RawRepresentable> : UserDefaultsVariable<T>{
    
    override var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }
    
    override func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}

let enumedDefault = RawRepresentableUserDefaultsVariable<Direction>(storageKey: "enumed", initialValue: .left)

let initialEnumValue = enumedDefault.value
class UserDefaultsVariable<T> : VariableType {

    let storageKey : String

    init(storageKey: String) {
        self.storageKey = storageKey
    }

    var value : T {

        get {
            return UserDefaults.standard.object(forKey: storageKey) as! T
        }

        set(value) {
            UserDefaults.standard.set(value, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey : initialValue])
    }

}

extension UserDefaultsVariable {

    // this initializer uses default T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }
}

extension UserDefaultsVariable where T: RawRepresentable {

    // this initializer uses specialised T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }

    var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}