【问题标题】:Does appending a list to another list in F# incur copying of underlying objects or just the pointers?将一个列表附加到 F# 中的另一个列表会导致复制底层对象还是仅复制指针?
【发布时间】:2012-08-19 11:20:28
【问题描述】:

我一直认为将一个列表附加到另一个列表意味着从第一个列表中复制对象,然后指向附加的列表,例如 here。 但是,在this 博客文章及其评论中,它说只有指针被复制,而不是底层对象。 那么什么是正确的呢?

【问题讨论】:

    标签: list f# functional-programming


    【解决方案1】:

    根据 Snowbear 的回答,组合两个列表的更准确图像(比问题中第一篇提到的文章中提供的图像)如下所示。

    let FIRST = [1;2;3]
    let SECOND = [4;5;6]
    let COMBINED = FIRST @ SECOND
    

    【讨论】:

    • 这基本上是正确的,但是为了混淆,这对于表示引用类型值的 1、2 和 3 是正确的。如果它们是值类型(例如int),那么它们实际上会被复制。
    【解决方案2】:

    在函数世界中,列表是不可变的。这意味着节点共享是可能的,因为原始列表永远不会改变。由于第一个列表以空列表结尾,因此必须复制其节点以将其最后一个节点指向第二个列表。

    如果你的意思是这个陈述,那么答案似乎很简单。第一篇文章的作者说nodes 时正在谈论列表节点元素。节点元素与列表项本身不同。看看第一篇文章中的图片。从每个元素到下一个节点都有箭头。这些箭头是指针。但是整数类型(放入列表中)没有这样的指针。可能有一些 list node 类型包装了这些整数并存储了指针。当作者说nodes must be copies 他是在谈论这些包装被复制。底层对象(如果它们不是本例中的值类型)将不会被克隆,新包装器将指向与以前相同的对象。

    【讨论】:

    • 那么第一篇文章中显示第一个、第二个和组合列表的图像有些误导,因为您得到的印象是基础对象也已被复制(值 1、2 和 3)。我想更准确的图像将是下面发布的图像。
    • @Christian,是的,该图像比文章中的图像更接近现实世界。我认为您应该将您的答案标记为已接受,因为您的图片价值千言万语。
    【解决方案3】:

    F# 列表包含对其元素的引用(不要与 F# 的 ref 混淆);列表操作复制这些引用(指针),但不复制元素本身。

    您可以通过两种方式将项目附加到现有列表,这就是文章之间似乎存在差异的原因(尽管它们看起来都是正确的):

    • Cons 运算符 (::):cons 运算符将单个项目添加到 F# 列表中,从而生成一个新列表。它非常快 (O(1)),因为它只需要调用一个非常简单的构造函数来生成新列表。
    • 附加运算符 (@):附加运算符将两个 F# 列表附加在一起,生成一个新列表。它没有那么快(O(n)),因为为了使组合列表的元素正确排序,它需要遍历运算符左侧的整个列表(因此复制可以从第一个元素开始该列表的)。如果已知左侧的列表非常小,您仍然会在生产环境中看到它,但通常使用 :: 可以获得更好的性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-02
      • 2017-11-02
      • 2015-11-28
      • 1970-01-01
      • 2016-11-08
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      相关资源
      最近更新 更多