问题
The following fails as per the error message quoted in the comment. It has been boiled down to the bare minimum, so the code below has no apparent practical value. I'm just trying to get a handle on the truly bizarre (in my opinion) error message. The reason I want to declare the array as [P]
and not [S]
is for the usual run-time polymorphism of the array contents.
protocol P {
func sp()
}
struct S: P {
func sp() {}
}
extension Array where Element: P {
func am() {}
}
func t() {
let goodA = [S]()
goodA.am() // No problem
let badA = [P]()
badA.am() // Error: '[P]' is not convertible to 'P'
}
回答1:
Protocol declarations define new independent types. While they do behave differently than classes, enums, and structs, they can act as the type for a variable or property (provided there are no associated type constraints, but hold on). For instance
protocol MyProtocol {}
let myConst: MyProtocol // myConst has type `MyProtocol`
In a protocol extension with a generic where clause, there are two different ways to constrain the generic type in question: either with :_
or ==
. There is a difference between the two.
Use of :_
The colon specifies that the generic type is something matching the type or protocol specified. It can be read as 'inherits from' or 'conforms to'. For example, anything specified in the extensions apply only when the associated type conforms to Equatable
or inherits from SomeClass
protocol AnotherProtocol {
associatedtype MyType
}
class SomeClass {}
extension AnotherProtocol where MyType: SomeClass {}
extension AnotherProtocol where MyType: Equatable {}
Use of ==
The ==
operator in a generic where clause specifies that the generic type is exactly the type specified and no other. The code below gives a compile-time error
class CustomType {}
class CustomTypeII: CustomType {}
class MyClass: AnotherProtocol { typealias MyType = CustomTypeII }
extension AnotherProtocol where MyType == CustomType {
func myFunc() {}
}
let instance = MyClass()
instance.myFunc() // Error: `CustomTypeII` is not the same type as `CustomType`
The ==
operator cannot be used to constrain a generic type to a protocol with associated types. The compiler will complain that the protocol has an associated type requirement.
protocol ThirdProtocol {}
extension ThirdProtocol where Self == AnotherProtocol {} // Error: `AnotherProtocol` has associated type requirements
In essence, the specification is ambiguous: there is no single AnotherProtocol
type, much in the same way that there is no single Array
type. The associated type in a protocol acts similarly to the generic arguments of a generic type. Here, the use of a colon is needed to specify that the generic type 'is some' AnotherProtocol
type (opaque types follow from the need to specify a specific 'type' of a protocol with associated type constraints, but that is beyond the question).
Your extensions
The extension of Array
applies only to array instances whose elements are some type that conforms to the protocol type P
, which does not apply to arrays whose elements are the type P
. Protocols not conforming to themselves is akin to classes not inheriting from themselves.
This is an old thread, but hopefully this helped.
来源:https://stackoverflow.com/questions/32741043/cant-call-extension-method-on-generic-array-class-when-element-type-is-a-protoc