考虑以下代码:
protocol JSONParserType {
associatedtype Element
}
// MARK: - Entities
struct Item {}
// MARK: - Parsers
struct OuterParser<T: JSONParserType where T.Element == Item>: JSONParserType {
typealias Element = Item
let innerParser: T
init(innerParser: T = InnerParser()) {
self.innerParser = innerParser
}
}
struct InnerParser: JSONParserType {
typealias Element = Item
}
该OuterParser
有一个孩子解析器应该被限制在一个特定的类型。不幸的是,在初始化器(或属性定义本身)中提供默认值会导致编译器抛出“无法将类型'InnerParser'的默认参数值转换为类型'T'”。
如果删除默认值分配并仅实例化显式OuterParser
提供InnerParser
,则一切正常。
let outerParser = OuterParser(innerParser: InnerParser())
我的问题是,提供实际上满足约束的默认值的方法不起作用的原因是什么?
问题在于实际的类型T
不是由类定义的,而是由使用该类的代码定义的。因此,它将在您在类中进行任何操作之前(在实例或静态级别)进行定义。因此,您无法分配InnerParser
给T
,因为T
该点已被定义为给定类型,而这可能不是InnerParser
。
例如,让我们考虑您有另一个解析器结构:
struct AnotherParser: JSONParserType {
typealias Element = Item
}
并假设您当前的代码已编译。现在考虑这样做时会发生什么:
let parser = OuterParser<AnotherParser>()
您已将通用类型定义为AnotherParser
–但初始化程序将尝试分配InnerParser
给您的属性(现在为类型AnotherParser
)。这些类型不匹配,因此可能无法正常工作。
按照相同的逻辑,此实现也将不起作用:
struct OuterParser<T: JSONParserType where T.Element == Item>: JSONParserType {
typealias Element = Item
let innerParser: T
init() {
self.innerParser = InnerParser()
}
init(innerParser: T) {
self.innerParser = innerParser
}
}
由于无法保证泛型类型T
将与相同InnerParser
。当然,您可以强制向下转换T
-但如果类型不兼容,这只会使您的代码崩溃。
不幸的是,没有真正的解决方案可以解决这个问题。我认为最好的最佳选择可能是创建两个工厂方法来创建OuterParser
实例。
enum Parser {
static func createParser() -> OuterParser<InnerParser> {
return OuterParser(innerParser:InnerParser())
}
static func createParser<T>(innerParser:T) -> OuterParser<T> {
return OuterParser(innerParser:innerParser)
}
}
let innerParser = Parser.createParser() // OuterParser<InnerParser>
let anotherParser = Parser.createParser(AnotherParser()) // OuterParser<AnotherParser>
我们在这里使用一个无大小写的枚举,以避免用额外的函数污染全局名称空间。
尽管这不是很迅速,但是出于这个原因,我也建议您重新考虑一下如何定义解析器的逻辑。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句