如何使用类型参数符合协议的泛型数组? [英] How would I use an array of generics with a type parameter conforming to a protocol?

查看:68
本文介绍了如何使用类型参数符合协议的泛型数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以使泛型数组(或实际上是任何泛型类型)具有符合协议的类型参数?

Is there a way to have an array (or any generic type really) of generics with a type parameter conforming to a protocol?

protocol MyProtocol {}

struct MyStruct<T: MyProtocol> {
  let myProp: T
}

// Generic parameter 'T' could not be inferred
// Explicitly specify the generic arguments to fix this issue
let array1 = [MyStruct]()

// Value of protocol type 'MyProtocol' cannot conform to 'MyProtocol';
// only struct/enum/class types can conform to protocols
let array2 = [MyStruct<MyProtocol>]()

// Type 'Any' does not conform to protocol 'MyProtocol'
let array3 = [MyStruct<Any>]()

protocol MyProtocol2 {
  associatedtype T = MyProtocol
  var myProp: T { get }
}
extension MyStruct: MyProtocol2 {}
// Protocol 'MyProtocol2' can only be used as a generic constraint because it has Self or 
// associated type requirements
let array4 = [MyProtocol2]()

该数组可以具有带有不同类型参数的 MyStruct .

The array can have MyStructs with a different type parameter.

理想情况下,这应该可行:

Ideally, this should work:

struct MyStruct2<T: MyProtocol> {
  let myProp: T
  let myFunc: (T) -> Void
}

let array = [MyStruct2</* something? */>]()
array.forEach { $0.myFunc($0.myProp) }


我已阅读协议只能用作通用约束,因为它具有Self或associatedType要求,但是该解决方案在我的情况下不起作用,因为数组中的项目为 MyStruct ,且任何类型都符合 MyProtocol .


I have read Protocol can only be used as a generic constraint because it has Self or associatedType requirements, but that solution does not work in my situation as the items in the array are MyStruct with any type that conforms to MyProtocol.

我还阅读了迅速将协议用作数组类型和函数参数以及其他类似问题,但是解决方案也不合适.

I have also read Usage of protocols as array types and function parameters in swift and other similar questions, but the solutions also aren't appropriate.

推荐答案

要了解您的方案有什么问题,请忘记尝试声明此数组的类型,并尝试实际 make 实际对象之外的数组:

To see what's wrong with your scenario, forget about trying to declare the type of this array, and try to actually make such an array out of actual objects:

protocol MyProtocol {}
struct MyStruct<T: MyProtocol> {
  let myProp: T
}
struct S1 : MyProtocol {}
struct S2 : MyProtocol {}
let myStruct1 = MyStruct(myProp: S1())
let myStruct2 = MyStruct(myProp: S2())
let array = [myStruct1, myStruct2] // error

编译器反冲:异构集合文字只能被推断为'[Any]'".总结一下. myStruct1 myStruct2 的类型没有什么共同之处,因此您不能将它们组成一个数组.

The compiler kicks back: "heterogeneous collection literal could only be inferred to '[Any]'". And that sums it up. The types of myStruct1 and myStruct2 have nothing in common, so you cannot make an array of them.

这就是为什么您不能将数组声明为包含两个数组的类型的原因.没有这种类型. myStruct1 myStruct2 的类型为 MyStruct< S1> 和 MyStruct< S2> 不相关.

That is why you are not able to declare the array to be of a type that will embrace both of them. There is no such type. The types of myStruct1 and myStruct2, namely MyStruct<S1> and MyStruct<S2>, are unrelated.

我知道它们 look 是相关的,因为原始声明中的"MyProtocol"一词似乎提供了某种共性.但是"MyProtocol"一词并未指定类型;它在实际类型上指定一个约束,表示无论该类型是什么,它都必须是MyProtocol的 adopter .S1和S2是两种不同的类型,因此 MyStruct< S1> MyStruct< S2> 是两种不同的类型.您不能将它们放在一个数组中.S1和S2都采用MyProtocol的事实是无关紧要的.

I know that they look related, because the word "MyProtocol" in the original declaration appears to provide some sort commonality. But the word "MyProtocol" does not designate a type; it designates a constraint on the actual type, saying that whatever this one type is, it must be an adopter of MyProtocol. S1 and S2 are two different types, and so MyStruct<S1> and MyStruct<S2> are two different types. You can't put them together in an array. The fact that both S1 and S2 happen to adopt MyProtocol is irrelevant.

部分困难可能是您认为两个泛型类型以某种方式相关,因为它们的参数化类型相关.事实并非如此.经典示例是一个类及其子类:

Part of the difficulty may be that you think that two generic types are somehow related because their parameterized types are related. That is not the case. The classic example is a class and its subclass:

class Cat {}
class Kitten: Cat {}
struct Animal<T: Cat> {}
let cat = Animal<Cat>()
let kitten = Animal<Kitten>()
let array2 = [cat, kitten] // error

我们得到相同的编译错误.再一次,您可能会想像可以将 cat kitten 放到一个数组中,因为Kitten是Cat的子类.但这是不正确的. Animal< Cat> Animal< Kitten> 不相关的类型.

We get the same compile error. Again, you might imagine that you can put cat and kitten together in an array because Kitten is a subclass of Cat. But that is not true. Animal<Cat> and Animal<Kitten> are unrelated types.

这篇关于如何使用类型参数符合协议的泛型数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆