Ceylon中列表,元组,序列,顺序,可迭代,数组等之间的区别

时间:2016-01-30 11:47:05

标签: collections ceylon

Ceylon对于可能被视为某种阵列的事物有几个不同的概念:ListTupleSequenceSequentialIterableArrayCollectionCategory等。这些类型的不同之处是什么?我应该何时使用它们?

2 个答案:

答案 0 :(得分:8)

在基本级别开始了解这些事情的最佳地点是Ceylon tour。深入了解这些事情的地方是module API。查看source files for these

也很有帮助

与所有优秀的现代编程语言一样,前几个接口都是超级抽象的。它们围绕一个正式成员构建,并通过一组默认和实际成员提供其功能。 (在Java 8之前创建的编程语言中,您可能听说过这些称为“traits”的区域,以区别于只有正式成员且没有功能的传统接口。)

分类

让我们首先谈谈界面Category。它表示您可以询问的类型“此集合是否包含此对象”,但您可能不一定能够从集合中获取任何成员。它的正式成员是:

shared formal Boolean contains(Element element)

一个例子可能是大数的所有因子的集合 - 你可以有效地测试任何整数是否是一个因素,但不能有效地得到所有因子。

可迭代

Category的子类型是接口Iterable。它表示一种类型,您可以从中一次获取一个元素,但不一定索引元素。元素可能没有明确定义的顺序。这些元素甚至可能尚不存在,但是在运行中生成。该系列甚至可能无限长!它的正式成员是:

shared formal Iterator<Element> iterator()

一个例子是标准输出的字符流。另一个例子是提供给for循环的一系列整数,为了一次生成一个数字,它的内存效率更高。

这是Ceylon中的一种特殊类型,可以缩写为{Element*}{Element+},具体取决于iterable是否为空或绝对不为空。

集合

Iterable的一个子类型是接口Collection。它有一个正式成员:

shared formal Collection<Element> clone()

但这并不重要。定义Collection的重要一点是文档中的这一行:

  

所有Collection都需要支持明确定义的价值观   平等,但平等的定义取决于那种   集合。

基本上,Collection是一个集合,其结构定义足以使彼此相等并且可克隆。这个对定义良好的结构的要求意味着这是超级抽象接口的最后一个,其余的看起来就像更熟悉的集合。

列表

Collection的一个子类型是接口List。它表示一个集合,其元素我们可以通过索引(myList[42])获得。当你的函数需要一个数组来解决问题时使用这种类型,但不关心它是可变的还是不可变的。它有一些正式的方法,但重要的方法来自其他超类型Correspondence

shared formal Item? get(Integer key)

顺序,顺序,空

最重要的List子类型是接口Sequential。它代表一个不可变的List。锡兰喜欢这种类型并围绕它构建了很多语法。它被称为[Element*]Element[]。它有两个子类型:

  • Empty(又名[]),代表空集合
  • Sequence(又名[Element+]),代表非空集合。

因为集合是不可变的,所以你可以用它们做很多事情,而不能用可变集合做。例如,许多操作可能会在nullfirst空列表中Sequence失败,但如果您先reduce,则可以保证这些操作始终成功,因为集合之后不能变空(毕竟它们是不可变的)。

元组

Sequence的一个非常特殊的子类型是test that the type is Sequence,这是此处列出的第一个真正的类。与Element不同,其中所有元素都被约束为一种类型Tuple[String, Integer, String]具有每个元素的类型。它在Ceylon中得到了特殊的语法,其中List是一个完全由三个元素组成的不可变列表,正好按照这个顺序排列。

阵列

{{1}}的另一个子类型是Tuple,也是一个真正的类。这是熟悉的Java数组,一个可变的固定大小的元素列表。

答案 1 :(得分:5)

drhagen已经很好地回答了你问题的第一部分,所以我只想对第二部分说一点:你什么时候使用哪种类型?

一般来说:在编写函数时,让它接受支持你需要的操作的最常规类型。到目前为止,很明显。

Category 非常抽象,很少有用。

如果您希望迭代某些元素流(或使用Iterable,{{1}等流操作),则应使用 filter 等等。)。

关于map要考虑的另一件事是它在命名参数中有一些额外的语法糖:

Iterable

Try online

类型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" }; 的任何参数都可以作为命名参数列表末尾的逗号分隔参数列表提供。也就是说,

Iterable

相当于

printAll { "a", "b", "c" };

这允许你制作DSL风格的表达; tour有一些不错的例子。

printAll { things = { "a", "b", "c" }; }; Collection一样,相当抽象,根据我的经验很少直接使用。

Correspondence 听起来应该是经常使用的类型,但实际上我不记得使用它了很多。我不知道为什么。我似乎跳过它并将我的参数声明为ListIterable

SequentialSequential 是您需要不可变的固定长度列表的时间。它还有一些语法糖:Sequence等变量方法是void foo(String* bar)Sequential参数的快捷方式。 Sequence还允许您使用Sequential运算符,该运算符通常可与nonemptyfirst结合使用:

rest

Try online

我通常会使用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 ""; } } Sequential当我要多次迭代一个流时(对于通用Sequence而言可能很昂贵),尽管Iterable可能是更好的界面。

List 永远不应该用作Tuple(除非在极少数情况下您将对其进行抽象),但使用Tuple语法糖它通常很有用。您通常可以将[X, Y, Z]成员细化为子类中的Sequential,例如: G。超类有一个Tuple,它在一个子类中被称为<String|Integer>[] elements

[String, Integer] elements 我从未用作参数类型,很少作为实例化和使用的类。