我试图了解序列和列表之间的区别。
在 F# 中,两者之间有明显的区别。但是在 C# 中,我看到程序员将 IEnumerable 集合称为序列。是什么让 IEnumerable 成为一个序列,它返回一个对象以遍历集合?
也许真正的区别纯粹是在函数式语言中发现的?
不是真的 - 你倾向于随机访问一个列表,以及能够快速获得它的计数等。不可否认的链接列表没有随机访问性质......但是他们没有实现IList<T>
. 特定平台提供的设施与一般概念之间存在灰色地带。
序列(由 表示IEnumerable<T>
)是只读的、只进的、一次一个项目,并且可能是无限的。当然,序列的任何一种实现也可能是一个列表(例如List<T>
),但是当您将其视为一个序列时,您基本上可以(重复地)对其进行迭代,仅此而已。
我认为这种混淆可能是由于集合之类List<T>
的实现接口这一事实引起的IEnumerable<T>
。如果您通常具有子类型关系(例如Shape
,具有两个子类型Rectangle
和的超类型Circle
),您可以将关系解释为“is-a”层次结构。
这意味着说“Circle
是一个 Shape
”是完全可以的,类似地,人们会说“List<T>
是一个 IEnumerable<T>
”,即“列表是一个序列”。这是有道理的,因为列表是序列的一种特殊类型。一般来说,序列也可以是惰性生成和无限的(这些类型也不能是列表)。无法由列表生成的(完全有效的)序列示例如下所示:
// C# version // F# version
IEnumerable<int> Numbers() { let rec loop n = seq {
int i = 0; yield n
while (true) yield return i++; yield! loop(n + 1) }
} let numbers = loop(0)
这对于 F# 也是如此,因为 F#list
类型也实现IEnumerable<T>
了 ,但函数式编程并没有那么强调面向对象的观点(并且在 F# 中不太频繁使用启用“is a”解释的隐式转换)。
序列内容是按需计算的,因此您可以在不影响记忆的情况下实现例如无限序列。所以在C#中你可以写一个序列,例如
IEnumerable<int> Null() {
yield return 0;
}
它将返回无限的零序列。你可以写
int[] array = Null().Take(10).ToArray()
尽管序列是无限的,但它将占用 10*4 字节的内存。如您所见,C# 确实区分了序列和集合