arrays - 为什么 count 返回 Collection 和 Array 的不同类型?

标签 arrays swift collections count associated-types

当我扩展 Collection 时,count 的类型是 IndexDistance

当我扩展 Array 类型时,countInt 类型

为什么会有这样的区分?这是最近的变化还是一直如此?

我读过这个answer但收不到太多。

唯一我认为相关但不理解的是:

Another advantage is that this[IndexDistance] also works correctly with array slices (where the index of the first element is not necessarily zero

不知道是什么意思。

我问的原因是,为什么代码在 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
        }
    }
}

编辑:

根据 Martin 和其他人的评论,我添加了一个额外的问题。可能这是我问题的根本原因......

这是否意味着在 Collection 中键入 IndexDistance 定义为 Int。基本上一般来说,在“协议(protocol)”级别,associatedTypes 未定义...它正在等待一个具体类型来做到这一点?那正确吗?

也就是说,在“协议(protocol)”级别访问 count 是否有任何有意义的用例?我的意思是您无法将它与任何 Int 进行比较,因此它看起来毫无用处。

最佳答案

来自 Associated Types在 Swift 编程语言中(添加了重点):

When defining a protocol, it’s sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name to a type that is used as part of the protocol. The actual type to use for that associated type isn’t specified until the protocol is adopted. Associated types are specified with the associatedtype keyword.

Swift 3/4.0中,Collection协议(protocol)定义了五种关联类型 (来自 What’s in a 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>
    ...
}

这里

    associatedtype IndexDistance: SignedInteger = Int

是一个带有类型约束(: SignedInteger)和默认值(= Int)的关联类型声明,

如果类型 T 采用协议(protocol)并且没有定义 T.IndexDistance 否则 T.IndexDistance 成为 的类型别名>整数。 许多标准集合类型都是这种情况 (例如 ArrayString),但不是所有的。例如

public struct AnyCollection<Element> : Collection

来自 Swift 标准库定义

    public typealias IndexDistance = IntMax

你可以用它来验证

let ac = AnyCollection([1, 2, 3])
let cnt = ac.count
print(type(of: cnt)) // Int64

如果愿意,您还可以使用非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
    }
}

因此,如果您扩展具体类型Array,那么count 是一个Int:

extension Array {
    func whatever() {
        let cnt = count // type is `Int`
    }
}

但是在协议(protocol)扩展方法中

extension Collection {
    func whatever() {
        let cnt = count // some `SignedInteger`
    }
}

你所知道的是 cnt 的类型是 some 采用 SignedInteger 协议(protocol),但不一定是 Int。一个还可以 当然是和伯爵一起工作。其实编译错误在

    for index in 0...count { //  binary operator '...' cannot be applied to operands of type 'Int' and 'Self.IndexDistance'

具有误导性。整数文字 0 可以推断为 Collection.IndexDistance 来自上下文(因为 SignedInteger 符合 ExpressibleByIntegerLiteral)。但是 SignedInteger 的范围不是 Sequence,这就是编译失败的原因。

所以这会起作用,例如:

extension Collection {
    func whatever() {
        for i in stride(from: 0, to: count, by: 1) {
            // ...
        }
    }
}

Swift 4.1 IndexDistance 不再使用,并且 集合索引之间的距离现在总是表示为 Int,请参阅

特别是 count 的返回类型是 Int。有一个类型别名

typealias IndexDistance = Int

使旧代码编译,但已被弃用并将被删除 在 Swift 的 future 版本中。

关于arrays - 为什么 count 返回 Collection 和 Array 的不同类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49540080/

相关文章:

string - Swift String 编码和 NSXMLParser 解析问题

java - 修改Map中对象的成员

javascript - 在对象数组javascript中查找并替换值

c# - 热逻辑比较 bool 数组与它自己的单个 bool 结果?

php - 添加到 $_SESSION 中的数组

python - 为什么更新附加到列表的字典会更改列表?

ios - 如何将按钮设置为可用视口(viewport)高度的一半?

generics - 简单的 Swift 泛型难题

java - 字符串操作的不合适输出

Java从ArrayList中删除整数的正确方法