I'm trying to write a protocol that conforms to the Collection Protocol, and it has an associatedType - Object and a property 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. It seems like it all works except for Collection's requirement for a subscript.
Cannot subscript a value of type 'Self.Object' with an index of type 'Self.Object.Index'
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
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)
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
subscript(position: Self.Index) -> Self.Element { get }
where Self.Index
and Self.Element
are associated types of `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]
). 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'; did you mean to use '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
subscript(position: Object.Index) -> Object.Element {
return object[position]
}
so that the compiler infers DDCDataSource.Element
to be Object.Element
.
Full self-contained example: (Swift 4, Xcode 9 beta 6)
(Note that you can omit the get
keyword for read-only computed properties.)
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
,
Secondly, you use object[position]
, Object Conforms To Collection , but it is not of Collection Types . Obviously it is not Array.
As apple says : array conforms to CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection
I think extension DDCDataSource where Object: Array
is better.
And the element in array shall be Element
defined. 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
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.