Hon*_*ney 14 arrays collections count associated-types swift
当我伸出Collection的类型count是IndexDistance.
当我扩展Array类型时count,类型Int
为什么会有这样的区别?这是最近的变化还是总是像这样?
我已经阅读了这个答案,但不能捡到太多.
我认为唯一相关但却不理解的是:
另一个优点是,[IndexDistance]也可以正确处理数组切片(其中第一个元素的索引不一定为零)
不确定那是什么意思.
我问的原因是为什么代码会在Collection上抛出错误但在Array上没有这样做...尽管两者count最终都是Int.
extension Collection where Element: Comparable{
func whatever(){
for index in 0...count{ // binary operator '...' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'
}
}
}
extension Array where Element: Comparable{
func whatever(){
for index in 0...count{ // NO ERROR
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
根据Martin和其他人的评论,我添加了一个额外的问题.可能这是我问题的根本原因......
这是否意味着中Collection类型IndexDistance 没有定义Int.基本上一般来说,在"协议"级别,关联类型没有被定义 ......它正在等待具体类型来做到这一点?是对的吗?
话虽如此,是否有任何有意义的用例访问count"协议"级别?我的意思是你无法将它与任何Int它进行比较所以它似乎没用.
Mar*_*n R 10
从Swift编程语言中的关联类型(重点补充):
在定义协议时,将一个或多个关联类型声明为协议定义的一部分有时很有用.关联类型为占用协议一部分的类型提供占位符名称.在采用协议之前,不会指定用于该关联类型的实际类型.使用associatedtype关键字指定关联类型.
在斯威夫特3/4.0,该Collection协议定义了五种类型的关联(从集合中的哪些内容?):
protocol Collection: Indexable, Sequence {
associatedtype Iterator: IteratorProtocol = IndexingIterator<Self>
associatedtype SubSequence: IndexableBase, Sequence = Slice<Self>
associatedtype Index: Comparable // declared in IndexableBase
associatedtype IndexDistance: SignedInteger = Int
associatedtype Indices: IndexableBase, Sequence = DefaultIndices<Self>
...
}
Run Code Online (Sandbox Code Playgroud)
这里
associatedtype IndexDistance: SignedInteger = Int
Run Code Online (Sandbox Code Playgroud)
是一个带有类型约束(: SignedInteger)和默认值(= Int)的关联类型声明,
如果类型T采用协议并且没有T.IndexDistance另外定义,则T.IndexDistance变为类型别名Int.许多标准集合类型(例如Array或String)都是这种情况,但不适用于所有类型.例如
public struct AnyCollection<Element> : Collection
Run Code Online (Sandbox Code Playgroud)
来自Swift标准库的定义
public typealias IndexDistance = IntMax
Run Code Online (Sandbox Code Playgroud)
您可以验证
let ac = AnyCollection([1, 2, 3])
let cnt = ac.count
print(type(of: cnt)) // Int64
Run Code Online (Sandbox Code Playgroud)
Int如果您愿意,还可以使用非索引距离定义自己的集合类型:
struct MyCollection : Collection {
typealias IndexDistance = Int16
var startIndex: Int { return 0 }
var endIndex: Int { return 3 }
subscript(position: Int) -> String {
return "\(position)"
}
func index(after i: Int) -> Int {
return i + 1
}
}
Run Code Online (Sandbox Code Playgroud)
因此,如果你扩展的具体类型Array则count
是Int:
extension Array {
func whatever() {
let cnt = count // type is `Int`
}
}
Run Code Online (Sandbox Code Playgroud)
但是在协议扩展方法中
extension Collection {
func whatever() {
let cnt = count // some `SignedInteger`
}
}
Run Code Online (Sandbox Code Playgroud)
你知道的一切都是采用协议的某种类型,但不一定cnt是这种类型
.当然,人们仍然可以使用伯爵.实际上编译错误了SignedIntegerInt
for index in 0...count { // binary operator '...' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'
Run Code Online (Sandbox Code Playgroud)
是误导.整数文字0可以Collection.IndexDistance从上下文中推断为
(因为SignedInteger
符合ExpressibleByIntegerLiteral).但是一系列SignedInteger不是a Sequence,这就是它无法编译的原因.
所以这可行,例如:
extension Collection {
func whatever() {
for i in stride(from: 0, to: count, by: 1) {
// ...
}
}
}
Run Code Online (Sandbox Code Playgroud)
从Swift 4.1开始, IndexDistance不再使用,并且集合索引之间的距离现在始终表示为a Int,请参阅
特别是返回类型count是Int.有一个类型别名
typealias IndexDistance = Int
Run Code Online (Sandbox Code Playgroud)
使旧的代码编译,但这已被弃用,将在未来的Swift版本中删除.