如何使用泛型在 Swift 中实现 "C++-ish template specialization"?

How do I achieve "C++-ish template specialization" in Swift with generics?

我知道泛型和模板是不同的,但我想我应该放弃 C++-ish 的评论,因为熟悉模板的人会知道我想要完成什么。在下面的代码中,我试图编写一个通用成员方法来处理一个重载变体中的字符串。在另一个变体中,该方法应该处理可以从字符串初始化的数字类型。

所以,下面,我想拿一张地图,给定一个特定类型的变量,在地图中查找名称并将其解析为正确的类型。不幸的是,我遇到了关于 type(of:) 上缺少 init() 的问题以及 Int 类型调用想要调用为字符串定义的方法的重载解析的问题。

代码如下:

protocol StringInitializable {
    init()
    init( _: String )
}

class Foo {
    var stringMember : String
    var intMember : Int

    var lookupMap : [String:String] = [
        "string" : "Your String",
        "int": "12"
    ]

    func extractType< ParseEntity: StringInitializable >( parameter: ParseEntity, lookupName: String ) throws -> ParseEntity? {
        var x : ParseEntity?
        x = type( of: ParseEntity ).init( lookupMap[ lookupName ] )
        return x
    }

    func extractType( parameter: String, lookupName: String ) throws -> String? {
        return lookupMap[ lookupName ]
    }

    init() {
        do {
            try extractType( parameter: stringMember, lookupName: "string" )
            try extractType( parameter: intMember, lookupName: "int")
        } catch {}
    }
}

代码有点乱,但希望足以传达其意图。任何帮助都表示赞赏。提前致谢。

我上面的公式有很多问题,但我最终得到了我想要的工作。

首先,在 StringInitializable 中,我需要以下内容:

protocol StringInitializable {
    init()
    init?(_ description: String)
}

其次,我必须通过协议扩展来扩展 Int 和 Float 以将它们标记为 "String Initializable":

extension Double : StringInitializable {}
extension Int : StringInitializable {}

第三,type(of:) 并不是 C++ 中 __decltype() 之类的纯粹替代品。我需要在 type(of:) 中构造一个 "ParseEntity"。所以在我重新编写的代码中,关键行看起来像这样:

    var x : ParseEntity? = type( of: ParseEntity() ).init( lookupMap[ lookupName ]! )

所以最终的 "working" 示例如下所示:

enum ParseError : Error {
    case BadParse( errorMessage: String)
}

protocol StringInitializable {
    init()
    init?(_ description: String)
}

extension Double : StringInitializable {}
extension Int : StringInitializable {}

class Foo {
    var stringMember : String = ""
    var intMember : Int = 0

    var lookupMap : [String:String] = [
        "string" : "Your String",
        "int": "12"
    ]

    func extractType< ParseEntity: StringInitializable >( parameter: ParseEntity, lookupName: String ) throws -> ParseEntity? {
        if let lookupEntry = lookupMap[ lookupName ] {
            return type( of: ParseEntity() ).init( lookupEntry )
        }
        throw ParseError.BadParse( errorMessage: "Bad parameter: \( lookupName )" )
    }

    func extractType( parameter: String, lookupName: String ) throws -> String? {
        if let lookupEntry = lookupMap[ lookupName ] {
            return lookupEntry
        }
        throw ParseError.BadParse( errorMessage: "Bad parameter: \( lookupName )" )
    }

    init() {
        do {
             stringMember = try extractType( parameter: stringMember, lookupName: "string" )!
             intMember = try extractType( parameter: intMember, lookupName: "int")!
        } catch ParseError.BadParse( let errorMessage ) {
            print( "\( errorMessage )" )
        } catch {}
    }
}


var f = Foo()
print( "\(f.intMember)" )
print( "\(f.stringMember)" )