我一直认为将一个列表附加到另一个列表意味着从第一个列表中复制对象,然后指向附加列表,例如此处所述。但是,在这篇博文及其评论中,它说只有指针被复制,而不是底层对象。那么什么是正确的呢?
问问题
591 次
3 回答
6
根据 Snowbear 的回答,组合两个列表的更准确图像(比问题中第一篇提到的文章中提供的图像)如下所示。
let FIRST = [1;2;3]
let SECOND = [4;5;6]
let COMBINED = FIRST @ SECOND
于 2012-08-19T19:21:59.750 回答
2
在函数世界中,列表是不可变的。这意味着节点共享是可能的,因为原始列表永远不会改变。因为第一个列表以空列表结尾,所以必须复制其节点以将其最后一个节点指向第二个列表。
如果你的意思是这个陈述,那么答案似乎很简单。第一篇文章的作者在谈到列表节点元素时说nodes
。节点元素与列表项本身不同。看看第一篇文章中的图片。从每个元素到下一个节点都有箭头。这些箭头是指针。但是整数类型(放入列表中)没有这样的指针。可能有某种list node
类型可以包装这些整数并存储指针。当作者说nodes must be copies
他正在谈论这些包装被复制时。底层对象(如果它们不是本例中的值类型)将不会被克隆,新的包装器将指向与以前相同的对象。
于 2012-08-19T12:04:10.967 回答
2
ref
F# 列表包含对其元素的引用(不要与 F# 混淆);列表操作复制那些引用(指针),但不复制元素本身。
有两种方法可以将项目附加到现有列表,这就是为什么文章之间似乎存在差异(尽管它们看起来都是正确的):
- Cons 运算符 (
::
):cons 运算符将单个项目添加到 F# 列表中,从而生成一个新列表。它非常快(O(1)
),因为它只需要调用一个非常简单的构造函数来生成新列表。 - 附加运算符 (
@
):附加运算符将两个 F# 列表附加在一起,生成一个新列表。它没有那么快(O(n)
),因为为了使组合列表的元素正确排序,它需要遍历运算符左侧的整个列表(因此复制可以从该列表的第一个元素开始)。如果已知左侧的列表非常小,您仍然会在生产中看到它,但通常使用::
.
于 2012-08-19T14:21:52.157 回答