如何在Swift中使用泛型实现“C++ - ish模板特化”?

问题描述:

我认识到泛型和模板是不同的,但我认为我会抛出C++ - ish的评论,因为熟悉模板的人会知道我正在尝试完成什么。在下面的代码中,我试图编写一个通用成员方法来处理一个过载变体中的字符串。在另一个变体中,该方法应该处理可以从字符串初始化的数字类型。如何在Swift中使用泛型实现“C++ - ish模板特化”?

因此,下面我想要一张地图,并给定一个特定类型的变量,在地图中查找名称并将其解析为正确的类型。不幸的是,我碰到了关于类型(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到它们标记为 “字符串Initializable”:

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

第三,类型(of :)不是像C++中的__decltype()这样的纯粹替换。我需要在(:)的类型中构造一个“ParseEntity”。因此,在我重新代码,临界线看起来是这样的:

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

所以最后的“工作”的例子看起来是这样的:

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)")