Swift 协议扩展,AssociatedType 被限制为集合,不能使用下标
Posted
技术标签:
【中文标题】Swift 协议扩展,AssociatedType 被限制为集合,不能使用下标【英文标题】:Swift Protocol Extension with AssociatedType Constrained to Collection, Can't Use Subscript 【发布时间】:2017-09-09 08:10:15 【问题描述】:我正在尝试编写一个符合 Collection Protocol 的协议,它有一个 associatedType - Object 和一个 property 对象。
protocol DDCDataSource: Collection
associatedtype Object
var object: Object get set
我想为 Object 也符合 Collection 协议的情况添加一些默认功能,即直接返回 Object 对这些必需的 Collection 属性和函数的实现。除了 Collection 对下标的要求之外,这一切似乎都有效。
不能用“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)
【问题讨论】:
请不要使用图片,而是添加代码sn-p。 我添加了标签 swift 3.2 因为它是 Xcode 9 特有的。在 Xcode 8 上你会有 "Use of undeclared type 'Element'".extension DDCDataSource where Object: RandomAccessCollection
,感觉好多了。
return object[position] as! Element
@Cœur:不,这会在运行时崩溃。
【参考方案1】:
简答:更改下标方法的返回类型
给Object.Element
subscript(position: Object.Index) -> Object.Element
return object[position]
或添加类型别名(与您为 Index
类型所做的类似方式)
typealias Element = Object.Element
subscript(position: Object.Index) -> Element
return object[position]
这使得代码按预期编译和运行。
解释:Collection
的subscript
method被声明为
subscript(position: Self.Index) -> Self.Element get
其中Self.Index
和Self.Element
是关联类型
的集合。用你的代码
subscript(position: Object.Index) -> Element
return object[position]
编译器将Self.Index
推断为Object.Index
,但是有
Self.Element
和 Object.Element
之间没有关系(即
由object[position]
返回)。错误变得更加明显
如果您添加显式演员表:
subscript(position: Object.Index) -> Element
return object[position] as Element
现在编译器抱怨
错误:“Self.Object.Element”不能转换为“Self.Element”;你的意思是用'as!'强制沮丧?
正确的解决方案是不是强制转换,而是让编译器
知道Self.Element
是Object.Element
,通过添加类型别名
或者通过改变返回类型
subscript(position: Object.Index) -> Object.Element
return object[position]
以便编译器推断 DDCDataSource.Element
为Object.Element
。
完整的独立示例:(Swift 4、Xcode 9 beta 6)
(请注意,对于只读计算,您可以省略 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
【讨论】:
【参考方案2】:首先,我认为你应该定义Element
,
其次,您使用 object[position]
,Object Conforms To Collection ,但它不是 Collection Types 。显然它不是数组。
作为apple says: 数组 符合 CustomDebugStringConvertible / CustomReflectable / CustomStringConvertible / CVarArg /Decodable / Encodable / ExpressibleByArrayLiteral /MutableCollection /RandomAccessCollection / RangeReplaceableCollection
我认为extension DDCDataSource where Object: Array
更好。
并且数组中的元素应为Element
定义。只是提示。
【讨论】:
这是一个协议,目标是让它非常通用,并允许使用它的类/结构来定义元素。我还希望 Object 适用于所有集合类型,而不仅仅是数组。 是的,协议很简短。我试图简化它。有点分而治之。谢谢你。我是 Swift 4 的新手。Element
对我来说似乎很奇怪。我得到了一些,虽然不如 Martin R。没有反对票很好。【参考方案3】:
试试这个:
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
【讨论】:
真的可以编译吗?object[position]
不是可选的。
是的,它不是可选的——但省略了保护语句,只返回 object[position] as!元素会编译。至于它是否会崩溃——我还没有尝试实际运行它。以上是关于Swift 协议扩展,AssociatedType 被限制为集合,不能使用下标的主要内容,如果未能解决你的问题,请参考以下文章