为什么计数返回不同类型的集合与数组? [英] Why does count return different types for Collection vs. Array?

查看:104
本文介绍了为什么计数返回不同类型的集合与数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When I'm extending Collection the type of count is IndexDistance.

当我扩展Array时,键入count的类型是Int

When I'm extending Array type the count is of type Int

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

Why is there such a distinction? Is this a recent change or it's always been like this?

我已经阅读了这个答案,但是收拾不了.

I've read this answer but couldn't pick up much.

我认为唯一但不了解的是:

The only thing I deemed related, but didn't understand was:

另一个优点是this [IndexDistance]也可以正常工作 与数组切片(其中第一个元素的索引不是 必须为零

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

不确定这是什么意思.

Not sure what that means.

我要问的原因是,为什么代码会在Collection上引发错误,而在Array上却不会这样……即使两个count最终都是Int.

The reason I'm asking is that why does the code throw an error on Collection but doesn't do such on Array...even though both counts are ultimately an 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
        }
    }
}

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

Based on comments made by Martin and others, I've added an extra question. Likely this is the root cause of my question...

这是否意味着在Collection中键入IndexDistance 不是定义为Int.基本上,通常在协议"级别,associatedTypes 未定义 ...正在等待 concrete 类型执行此操作?是对的吗?

Does it mean that within Collection type the IndexDistance isn't defined to Int. Basically in general at the 'Protocol' level associatedTypes aren't defined...It's waiting for a concrete type to do that? Is that right?

话虽如此,在协议"级别访问count是否有有意义的用例?我的意思是,您无法将其与任何Int进行比较,因此似乎毫无用处.

That being said is there any meaningful use case for accessing count at the 'Protocol' level? I mean you can't compare it against any Int so it seems pretty useless.

推荐答案

来自

From Associated Types in the Swift Programming Language (emphasis added):

在定义协议时,有时可以将一个或多个关联类型声明为协议定义的一部分.关联的类型为用作协议一部分的类型赋予占位符名称. 在采用协议之前,不指定要用于该关联类型的实际类型.关联类型是使用associatedtype关键字指定的.

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协议定义了五种相关类型 (摘自集合中有什么?):

In Swift 3/4.0, the Collection protocol defines five associated types (from 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)的关联类型声明,

is an associated type declaration with a type constraint (: SignedInteger) and a default value (= Int),

如果类型T采用协议且未定义T.IndexDistance,则T.IndexDistance成为Int的类型别名. 许多标准收集类型就是这种情况 (例如ArrayString),但不是全部.例如

If a type T adopts the protocol and does not define T.IndexDistance otherwise then T.IndexDistance becomes a type alias for Int. This is the case for many of the standard collection types (such as Array or String), but not for all. For example

public struct AnyCollection<Element> : Collection

Swift标准库中的定义

from the Swift standard library defines

    public typealias IndexDistance = IntMax

可以用来验证的

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

如果愿意,还可以使用非Int索引距离来定义自己的集合类型:

You can also define your own collection type with a non-Int index distance if you like:

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,则countInt:

Therefore, if you extend the concrete type Array then count is an Int:

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

但是在协议扩展方法中

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

您所知道的是cnt的类型是 some 类型,采用 SignedInteger协议,但不必为Int.一个人仍然可以 当然,与伯爵一起工作.实际上是

everything you know is that the type of cnt is some type adopting the SignedInteger protocol, but that need not be Int. One can still work with the count, of course. Actually the compiler error in

    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,这就是为什么它无法编译的原因.

is misleading. The integer literal 0 could be inferred as a Collection.IndexDistance from the context (because SignedInteger conforms to ExpressibleByIntegerLiteral). But a range of SignedInteger is not a Sequence, and that's why it fails to compile.

所以这可以工作,例如:

So this would work, for example:

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


Swift 4.1起IndexDistance不再使用,并且 集合索引之间的距离现在始终表示为Int,请参见


As of Swift 4.1, IndexDistance is no longer used, and the distance between collection indices is now always expressed as an Int, see

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

In particular the return type of count is Int. There is a type alias

typealias IndexDistance = Int

使较旧的代码编译,但已标记为已弃用,将被删除 在以后的Swift版本中.

to make older code compile, but that is remarked deprecated and will be removed in a future version of Swift.

这篇关于为什么计数返回不同类型的集合与数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆