我想我们都已经看到Dijkstra的著名论点 ,即应该使用包含性下限和排除性上限来表示自然数范围,并且作为推论,数组应从0开始索引。推理,尽管它未能考虑到几个反对意见,包括:
- 对于包含负整数的范围,包含性下限/排除性上限组合(称为Dijkstra range )是不自然的。 范围
start<=i<=0
将被写为start<=i<1
。 Dijkstra范围令人讨厌! - 从零开始的索引在访问数组的最后一个元素或从数组末尾进行索引时非常不便。 谁喜欢
array[length-i-1]
? 至少可以说,这种不便超过了能够写入0<=i<length
而不是1<=i<length+1
的便利,因此, 即使我们接受了他的论点 ,Dijkstra的情况也从零开始,从而大大破坏了这种情况。 迪克斯特拉山脉! - 不是两个端点是指定整数范围的唯一方法!
Ceylon没有传统的for
循环,并且我们不会通过遍历列表的索引来迭代列表元素。 尽管如此,我们仍然需要一种表达整数范围的方法。 我们对这个问题的解决方案与其他语言略有不同,并且部分地拒绝了Dijkstra的结论,因此值得解释其背后的原因。
范围
我们的设计基于这样的观察: 在实践中 ,我们几乎永远不会自然地发现自己具有包含性下限/排除性上界组合。 在我们的程序中自然产生的几乎总是以下两者之一:
- 两个(包括)端点,或
- (包括)起点和长度。
使用Dijkstra范围,我们可以表达两种情况而不会带来太多不适:
-
start<=i<end+1
-
start<=i<start+length
因此,我们可以将Dijkstra范围的传统用法视为这两种情况之间的一种折衷:一种选择,它不会使任何选择都太痛苦。
但是,当然,通过清楚地区分这两种常见情况,很明显,这两种情况都可以进一步优化。 因此,Ceylon提供了两种表示整数范围的选项:
- 范围运算符使用两个端点将范围表示为
start..end
。 在end<start
的情况下,范围为递减值。 在end==start
的情况下,范围恰好具有一个值。 - 分段范围运算符将范围的起点和长度表示为
start:length
。 在长度为非正数的情况下,范围为空。
因此,这种形式的传统C风格的for
循环:
for (i=0; i<length; i++) { ... }
是这样写的:
for (i in 0:length) { ... }
现在,由于整数不是我们可以形成的唯一范围,因此..
和:
运算符可以推广为满足接口Ordinal & Comparable<T>
任何类型T
因此,例如,我们可以像这样迭代英语字母的字母:
for (c in 'a'..'z') { ... }
切片
一个密切相关的问题是“切片”列表。 Python使用Dijkstra范围表示列表的一部分,因此list[start:end]
包含元素list[start], list[start+1], ..., list[end-1]
。 由于上面已经给出的原因,这是一个合理的折衷。
锡兰更好,为您提供以下选择:
- span运算符,为元素
list[start], list[start+1], ..., list[end]
编写了list[start..end]
list[start], list[start+1], ..., list[end]
。 - 段运算符,为元素
list[start], list[start+1], ..., list[start+length-1]
编写了list[start:length]
list[start], list[start+1], ..., list[start+length-1]
。
span和segment运算符是根据相当抽象的接口Ranged
,因此不仅仅适用于List
。 例如,平台模块ceylon.collection
允许您使用这些运算符来表示SortedMap
或SortedSet
子范围。
翻译自: https://www.javacodegeeks.com/2014/05/ranges-and-slices.html