drh*_*gen 6 collections ceylon
锡兰有可能都被认为是某种数组的东西几个不同的概念:List
,Tuple
,Sequence
,Sequential
,Iterable
,Array
,Collection
,Category
,等什么是这些这些类型,我应该何时使用它们有什么不同?
锡兰之旅是在基层开始学习这些东西的最佳地点.深入了解这些事情的地方是模块API.查看这些文件的源文件也很有帮助.
像所有优秀的现代编程语言一样,前几个接口都是超级抽象的.它们围绕一个正式成员构建,并通过一组默认和实际成员提供其功能.(在Java 8之前创建的编程语言中,您可能听说过这些称为"traits"的区域,以区别于只有正式成员且没有功能的传统接口.)
让我们从谈论界面开始吧Category
.它表示您可以询问的类型"此集合是否包含此对象",但您可能不一定能够从集合中获取任何成员.它的正式成员是:
shared formal Boolean contains(Element element)
Run Code Online (Sandbox Code Playgroud)
一个例子可能是大数的所有因子的集合 - 你可以有效地测试任何整数是否是一个因素,但不能有效地获得所有因子.
子类型Category
是接口Iterable
.它表示一种类型,您可以从中一次获取一个元素,但不一定索引元素.元素可能没有明确定义的顺序.这些元素甚至可能尚不存在,但是在运行中生成.该系列甚至可能无限长!它的正式成员是:
shared formal Iterator<Element> iterator()
Run Code Online (Sandbox Code Playgroud)
一个例子是标准输出的字符流.另一个例子是提供给for循环的一系列整数,为了一次生成一个数字,它的内存效率更高.
这是Ceylon中的一种特殊类型,可以缩写{Element*}
或{Element+}
取决于iterable是否为空或绝对不为空.
其中一个Iterable
子类型是界面Collection
.它有一个正式成员:
shared formal Collection<Element> clone()
Run Code Online (Sandbox Code Playgroud)
但这并不重要.定义a的重要一点Collection
是文档中的这一行:
所有人
Collection
都需要支持明确定义的价值平等概念,但平等的定义取决于收集的类型.
基本上,a Collection
是一个集合,其结构定义明确,足以彼此相等并且可克隆.对于定义良好的结构的这种要求意味着这是超级抽象接口的最后一个,其余的看起来就像更熟悉的集合.
其中一个Collection
子类型是界面List
.它表示一个集合,其元素可以通过index(myList[42]
)获得.当你的函数需要一个数组来解决问题时使用这种类型,但不关心它是可变的还是不可变的.它有一些正式的方法,但重要的方法来自其他超类型Correspondence
:
shared formal Item? get(Integer key)
Run Code Online (Sandbox Code Playgroud)
最重要List
的子类型是界面Sequential
.它代表了一个不可改变的List
.锡兰喜欢这种类型并围绕它构建了很多语法.它被称为[Element*]
和Element[]
.它有两个子类型:
Empty
(又名[]
),代表空集合Sequence
(又名[Element+]
),代表非空集合.因为集合是不可变的,所以你可以用它们做很多事情,而不能用可变集合做.首先,许多操作可以null
在空列表上失败,例如reduce
和first
,但是如果你首先测试类型是Sequence
那么你可以保证这些操作总是成功,因为集合以后不能变为空(毕竟它们是不可变的) .
一个非常特殊的亚型Sequence
是Tuple
,这里所列出的第一个真正的类.与Sequence
所有元素都被约束为一种类型的情况不同Element
,a Tuple
对每个元素都有一个类型.它在Ceylon中获得了特殊的语法,其中[String, Integer, String]
包含三个元素的不可变列表,这些元素恰好按照这个顺序排列.
另一个亚型List
是Array
,也是一个真正的类.这是熟悉的Java数组,一个可变的固定大小的元素列表.
drhagen已经很好地回答了你问题的第一部分,所以我只想对第二部分说一点:你什么时候使用哪种?
通常:在编写函数时,使其接受支持所需操作的最常规类型.到目前为止,这么明显.
Category
是非常抽象的,很少有用.
Iterable
如果你希望你只是要遍历(或使用流操作的相同部件的一些应使用流filter
,map
等等).
另一件要考虑的事情Iterable
是它在命名参数中有一些额外的语法糖:
void printAll({Anything*} things, String prefix = "") {
for (thing in things) {
print(prefix + (thing?.string else "<null>"));
}
}
printAll { "a", "b", "c" };
printAll { prefix = "X"; "a", "b", "c" };
Run Code Online (Sandbox Code Playgroud)
任何类型的参数Iterable
都可以作为命名参数列表末尾的逗号分隔参数列表提供.那是,
printAll { "a", "b", "c" };
Run Code Online (Sandbox Code Playgroud)
相当于
printAll { things = { "a", "b", "c" }; };
Run Code Online (Sandbox Code Playgroud)
这允许您制作DSL风格的表达; 这次旅行有一些很好的例子.
Collection
就像Correspondence
,相当抽象,根据我的经验很少直接使用.
List
听起来它应该是一个经常使用的类型,但实际上我不记得使用它很多.我不知道为什么.我似乎跳过它并将我的参数声明为Iterable
或者Sequential
.
Sequential
而Sequence
当你想在一个不变的,固定长度的列表.它也有一些语法糖:变量方法就像void foo(String* bar)
是一个Sequential
或Sequence
参数的快捷方式.Sequential
还允许您使用nonempty
操作符,这通常first
与rest
以下组合很好地结合使用:
String commaSeparated(String[] strings) {
if (nonempty strings) {
value sb = StringBuilder();
sb.append(strings.first); // known to exist
for (string in strings.rest) { // skip the first one
sb.append(", ").append(string);
// we don’t need a separate boolean to track if we need the comma or not :)
}
return sb.string;
} else {
return "";
}
}
Run Code Online (Sandbox Code Playgroud)
我经常使用Sequential
,Sequence
当我要多次迭代一个流时(这对于泛型来说可能很昂贵Iterable
),尽管List
可能是更好的接口.
Tuple
永远不应该被用作Tuple
(除非在极少数情况下你将它们抽象出来),但是使用[X, Y, Z]
语法糖它通常是有用的.您通常可以将Sequential
成员细化Tuple
为子类中的a,e.G.超类有<String|Integer>[] elements
一个子类中的一个是已知的[String, Integer] elements
.
Array
我从来没有用过参数类型,很少作为实例化和使用的类.