F# 中的缺点运算符 (::) 性能
cons operator (::) performance in F#
在官方文档中说 ::
比 @
快。
一旦所有列表在 F# 中都是不可变的,为什么会有差异?在任何情况下都应复制原始列表。但是如果是 ::
我们会在前面加上,而如果是 @
我们会追加。它应该是相同的复杂性。
有什么区别?
你的假设不正确。
当您在前面添加 ::
时,原始列表是 而不是 ,实际上是复制的。原始列表保留在内存中的原处,新列表现在由新元素和指向原始列表的指针组成,即它的尾部。
考虑一下:
let x = [1;2;3]
let y = 4 :: x
该程序将产生以下内存布局:
y -> 4
\
v
1 -> 2 -> 3 -> (END)
^
/
x
这是唯一可能的因为列表是不可变的:因为我们知道原始列表永远不会改变,所以我们可以将其征用为新列表的尾部。
这种排列一般称为“persistent data structure”。 Singly-linked 列表只是此类结构中最简单的一种。
另一方面,当追加 @
时,您确实必须复制整个原始列表。您不能重复使用它的任何部分。
这就是前置速度更快的原因。
在官方文档中说 ::
比 @
快。
一旦所有列表在 F# 中都是不可变的,为什么会有差异?在任何情况下都应复制原始列表。但是如果是 ::
我们会在前面加上,而如果是 @
我们会追加。它应该是相同的复杂性。
有什么区别?
你的假设不正确。
当您在前面添加 ::
时,原始列表是 而不是 ,实际上是复制的。原始列表保留在内存中的原处,新列表现在由新元素和指向原始列表的指针组成,即它的尾部。
考虑一下:
let x = [1;2;3]
let y = 4 :: x
该程序将产生以下内存布局:
y -> 4
\
v
1 -> 2 -> 3 -> (END)
^
/
x
这是唯一可能的因为列表是不可变的:因为我们知道原始列表永远不会改变,所以我们可以将其征用为新列表的尾部。
这种排列一般称为“persistent data structure”。 Singly-linked 列表只是此类结构中最简单的一种。
另一方面,当追加 @
时,您确实必须复制整个原始列表。您不能重复使用它的任何部分。
这就是前置速度更快的原因。