如何在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)")