当我扩展 Collection 时,count 的类型是 IndexDistance。
当我扩展 Array 类型时,count 是 Int 类型
为什么会有这样的区分?这是最近的变化还是一直如此?
我读过这个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 成为 的类型别名>整数。
许多标准集合类型都是这种情况
(例如 Array 或 String),但不是所有的。例如
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/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
通过rubykoans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)