protocol ParentProtocol { }
protocol ChildProtocol: ParentProtocol { }
protocol Child_With_Value_Protocol: ParentProtocol {
associatedType Value
func retrieveValue() -> Value
}尝试创建一个类型为ParentProtocol的单一数组,该数组包含、、ChildProtocol和Child_With_Value_Protocol。是否有可能创建一个函数,该函数遍历异构数组并返回仅键入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错误中失败,这是有意义的,因为编译器在转换为Child_With_Value_Protocol时不知道类型,这将导致下一个失败的解决方案。
尝试失败的解决方案#2
如果该数组是一个仅为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)?
}发布于 2016-07-03 11:54:00
先前的评论可能是正确的。不过,您可以将变体放在枚举中并创建这些变量的数组。然后,引用将打开enum值,每个值都具有正确类型的关联数据。
编辑:我没有费心于associatedValue,因为它似乎与被问的问题无关。下列作品在操场上进行:
protocol ParentProtocol: CustomStringConvertible {
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol]
}
protocol ChildProtocol: ParentProtocol { }
protocol Other_Child_Protocol: ParentProtocol { }
enum FamilyBox {
case Parent(parent: ParentProtocol)
case Child(child: ChildProtocol)
case OtherChildProtocol(withValue: Other_Child_Protocol)
}
var parents: [FamilyBox] = []
struct P: ParentProtocol {
var description: String { return "Parent" }
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol] {
var values = [ParentProtocol]()
for parent in parents {
switch parent {
case .Parent(let elementValue):
values.append(elementValue)
default:
break;
}
}
return values
}
}
struct C: ChildProtocol {
var description: String { return "Child" }
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol] {
var values = [ParentProtocol]()
for parent in parents {
switch parent {
case .Child(let elementValue):
values.append(elementValue)
default:
break;
}
}
return values
}
}
struct CV: Other_Child_Protocol {
var description: String { return "Other Child" }
static func retrieveValues(parents: [FamilyBox]) -> [ParentProtocol] {
var values = [ParentProtocol]()
for parent in parents {
switch parent {
case .OtherChildProtocol(let elementValue):
values.append(elementValue)
default:
break;
}
}
return values
}
}
let p = FamilyBox.Parent(parent: P())
let c = FamilyBox.Child(child: C())
let cv = FamilyBox.OtherChildProtocol(withValue: CV())
let array:[FamilyBox] = [p, c, cv]
print(P.retrieveValues(array))
print(C.retrieveValues(array))
print(CV.retrieveValues(array))最后三行的指纹如下:
[Parent]
[Child]
[Other Child]虽然我确信它可以改进,但我认为满足了最初的意图。不是吗?
https://stackoverflow.com/questions/38165878
复制相似问题