【问题标题】:Ruby passing arguments: difference between Array and SetRuby 传递参数:Array 和 Set 之间的区别
【发布时间】:2026-01-25 08:30:02
【问题描述】:

我正在尝试将一个数组放到另一个现有数组中,并且将其所有项目放到一个现有集合中。这是最小的示例:

require "set"

def add(myarr, bigarr, myset)
    bigarr << myarr
    myset |= Set.new(myarr)
end

bigarr = []
myset = Set.new

add([1, 2], bigarr, myset)

产生bigarr = [1, 2] .. 好的,但是myset = {} .. 是空的。我对在 Ruby 中传递参数知之甚少(应该是按值)——如果是数组,值应该是对其内容的引用,那么我不知道 set 的值可能是什么。

问题是:

  1. 导致此行为的ArraySet 之间的实质性区别是什么?
  2. 是否有任何方法可以强制 Ruby 传递引用,或者是否有其他推荐的方法来解决引用问题?

提前致谢!

【问题讨论】:

    标签: ruby pass-by-reference pass-by-value


    【解决方案1】:

    这里的问题实际上来自这一行:

     myset |= Set.new(myarr)
    

    在这里,您将在旧变量名称上创建新对象。您正在用另一个指针替换一个指针,但这只会修改它的本地副本。原始对象仍将存在于内存和外部函数中,指针将指向旧对象(空集)(tbh:我真的不鼓励这种带有副作用的 ruby​​ 编写)。

    如果你改成

    require "set"
    
    def add(myarr, bigarr, myset)
        bigarr << myarr
        myset.add(myarr)
    end
    
    bigarr = []
    myset = Set.new
    
    add([1, 2], bigarr, myset)
    

    它工作正常 - 因为您修改现有对象而不创建新对象。

    这里有一个很好的答案可以更彻底地解决这个问题:https://*.com/a/16464640/1975116

    【讨论】:

    • 基于myset |= Set.new(myarr),OP 似乎想将 myarr 的内容合并到集合中,而不是添加数组本身。
    • 没错,@Chuck 的回答完成了它应该做的事情。 #merge 方法修改现有实例,|= 创建新实例。谢谢,我现在明白了。
    【解决方案2】:

    这与数组和集合的区别没有任何关系。您正在使用 &lt;&lt; 方法修改数组,但您正在使用 |= 运算符重新分配 myset 变量。你永远不会修改你传入的集合。你想要的可能是myset.merge(myarr)

    【讨论】:

    • 很好的答案,我只是认为OP旨在使用||=|=是位运算符,在这种情况下没有意义。
    • @MichaelSzyndel:Fixnums 和 Bignums 是按位或,但 Set 和 Array 使用它作为集合联合运算符。我认为操作符在语义上是正确的,但问题在于 OP 想要一个破坏性操作,而 | 不是。
    • 你能指出我的文档吗?在 Set/Array 和 Enumerable 中都看不到它。
    • @MichaelSzyndel Set#|
    • @MichaelSzyndel:是的,Ruby 以这种方式对后面跟 = 的任何运算符进行脱糖。