protocol ParentProtocol { }
protocol ChildProtocol: ParentProtocol { }
protocol Child_With_Value_Protocol: ParentProtocol {
associatedType Value
func retrieveValue() -> Value
}
尝试创建一个ParentProtocol
包含和 ChildProtocol
的类型数组Child_With_Value_Protocol
。有没有可能的方法来创建一个循环遍历异构数组并返回只是 type 的值的函数Child_With_Value_Protocol
?
这可能需要架构更改。对所有解决方案开放。
尝试失败的解决方案 #1
var parents: [ParentProtocol] = [...both ChildProtocol & Child_With_Value_Protocol...]
func retrieveValues() -> [Any] {
var values = [Any]()
for parent in parents {
if let childWithValue = parent as? Child_With_Value_Protocol { // Fails to compile
values.append(childWithValue.retrieveValue())
}
}
return values
}
protocol 'Child_With_Value_Protocol' can only be used as a generic constraint because it has Self or associated type requirements
由于编译器在转换为 just 时不知道类型,因此失败并出现错误Child_With_Value_Protocol
,这会导致下一个失败的解决方案。
尝试失败的解决方案 #2
如果数组是 just 的同构数组,则Child_With_Value_Protocol
可以使用类型擦除来检索值。
var parents: [ParentProtocol] = [...both ChildProtocol & Child_With_Value_Protocol...]
struct AnyValue {
init<T: Child_With_Value_Protocol>(_ protocol: T) {
_retrieveValue = protocol.retrieveValue as () -> Any
}
func retrieveValue() -> Any { return _retrieveValue() }
let _retrieveValue: () -> Any
}
func retrieveValues() -> [Any] {
var values = [Any]()
for parent in parents {
values.append(AnyValue(parent).retrieveValue()) // Fails to compile
}
return values
}
由于结构AnyValue
没有用于ParentProtocol
.
尝试失败的解决方案#3
struct AnyValue {
init<T: Child_With_Value_Protocol>(_ protocol: T) {
_retrieveValue = protocol.retrieveValue as () -> Any
}
func retrieveValue() -> Any { return _retrieveValue() }
let _retrieveValue: () -> Any
}
var erased: [AnyValue] = [AnyValue(...), AnyValue(...), AnyValue(...)]
func retrieveValues() -> [Any] {
var values = [Any]()
for value in erased {
values.append(value.retrieveValue())
}
return values
}
与其他解决方案不同,此解决方案实际上可以编译。这个解决方案的问题在于数组erased
只能保存类型擦除版本的值Child_With_Value_Protocol
。目标是让数组同时保存和 Child_With_Value_Protocol
的类型ChildProtocol
。
尝试失败的解决方案#4
修改类型擦除结构以包含初始化程序ParentProtocol
仍然会创建一个可编译的解决方案,但是该结构将仅使用不太具体的 init,而不是更具体的 init。
struct AnyValue {
init?<T: ParentProtocol>(_ protocol: T) {
return nil
}
init?<T: Child_With_Value_Protocol>(_ protocol: T) {
_retrieveValue = protocol.retrieveValue as () -> Any
}
func retrieveValue() -> Any { return _retrieveValue() }
let _retrieveValue: (() -> Any)?
}