[英]Swift Protocol Extension with AssociatedType Constrained to Collection, Can't Use Subscript
I'm trying to write a protocol that conforms to the Collection Protocol, and it has an associatedType - Object and a property object. 我正在尝试编写符合集合协议的协议,它有一个associatedType - Object和一个属性对象。
protocol DDCDataSource: Collection
{
associatedtype Object
var object: Object {get set}
}
I want to add some default functionality for the case where Object also conforms to the Collection protocol, namely just directly return Object's implementation of these required Collection properties and functions. 我想为Object也符合Collection协议的情况添加一些默认功能,即直接返回Object对这些必需Collection属性和函数的实现。 It seems like it all works except for Collection's requirement for a subscript.
除了Collection对下标的要求外,它似乎都有效。
Cannot subscript a value of type 'Self.Object' with an index of type 'Self.Object.Index'
无法使用类型为“Self.Object.Index”的索引下标“Self.Object”类型的值
extension DDCDataSource where Object: Collection
{
typealias Index = Object.Index
var startIndex: Object.Index {
get {
return object.startIndex
}
}
var endIndex: Object.Index {
get {
return object.endIndex
}
}
subscript(position: Object.Index) -> Element
{
return object[position]
}
func index(after i: Object.Index) -> Object.Index {
return object.index(after: i)
}
}
Short answer: Change the return type of the subscript method to Object.Element
简答:将下标方法的返回类型更改为
Object.Element
subscript(position: Object.Index) -> Object.Element {
return object[position]
}
or add a type alias (in a similar way as you did for the Index
type) 或添加类型别名(以与您对
Index
类型类似的方式)
typealias Element = Object.Element
subscript(position: Object.Index) -> Element {
return object[position]
}
That makes the code compile and run as expected. 这使得代码按预期编译和运行。
Explanation: The subscript
method of Collection
is declared as 说明:
Collection
的subscript
方法声明为
subscript(position: Self.Index) -> Self.Element { get }
where Self.Index
and Self.Element
are associated types of `Collection. 其中
Self.Index
和Self.Element
是`Collection的关联类型。 With your code 用你的代码
subscript(position: Object.Index) -> Element {
return object[position]
}
the compiler infers Self.Index
to be Object.Index
, but there is no relation between Self.Element
and Object.Element
(which is returned by object[position]
). 编译器推断
Self.Index
是Object.Index
,但没有关系Self.Element
和Object.Element
(其由返回object[position]
)。 The error becomes more apparent if you add an explicit cast: 如果添加显式强制转换,则错误会更明显:
subscript(position: Object.Index) -> Element {
return object[position] as Element
}
Now the compiler complains 现在编译器抱怨了
error: 'Self.Object.Element' is not convertible to 'Self.Element';
错误:'Self.Object.Element'不能转换为'Self.Element'; did you mean to use 'as!'
你的意思是用'as!' to force downcast?
迫使低垂?
The correct solution is not the forced cast but to make the compiler know that Self.Element
is Object.Element
, by adding a type alias or by changing the return type 正确的解决方案不是强制转换,而是通过添加类型别名或通过更改返回类型使编译器知道
Self.Element
是Object.Element
subscript(position: Object.Index) -> Object.Element {
return object[position]
}
so that the compiler infers DDCDataSource.Element
to be Object.Element
. 这样编译器
DDCDataSource.Element
将DDCDataSource.Element
推断为Object.Element
。
Full self-contained example: (Swift 4, Xcode 9 beta 6) 完整的自包含示例:( Swift 4,Xcode 9 beta 6)
(Note that you can omit the get
keyword for read-only computed properties.) (请注意,您可以省略只读计算属性的
get
关键字。)
protocol DDCDataSource: Collection {
associatedtype Object
var object: Object { get set }
}
extension DDCDataSource where Object: Collection {
var startIndex: Object.Index {
return object.startIndex
}
var endIndex: Object.Index {
return object.endIndex
}
subscript(position: Object.Index) -> Object.Element {
return object[position]
}
func index(after i: Object.Index) -> Object.Index {
return object.index(after: i)
}
}
struct MyDataSource: DDCDataSource {
var object = [1, 2, 3]
}
let mds = MyDataSource()
print(mds[1]) // 2
for x in mds { print(x) } // 1 2 3
Firstly, I think you should define Element
, 首先,我认为你应该定义
Element
,
Secondly, you use object[position]
, Object Conforms To Collection , but it is not of Collection Types . 其次,您使用
object[position]
,Object Conforms To Collection,但它不是Collection Types。 Obviously it is not Array. 显然它不是Array。
As apple says : array conforms to CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection
正如苹果所说 :数组符合CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg / Decodable / Encodable / ExpressibleByArrayLiteral / MutableCollection / RandomAccessCollection / RangeReplaceableCollection
I think extension DDCDataSource where Object: Array
is better. 我认为
extension DDCDataSource where Object: Array
更好。
And the element in array shall be Element
defined. 并且数组中的元素应该是
Element
定义的。 Just tips. 只是提示。
Try this: 试试这个:
subscript(position:Object.Index) -> Element
{
var element: Element
guard let elementObject = object[position] else {
//handle the case of 'object' being 'nil' and exit the current scope
}
element = elementObject as! Element
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.