【问题标题】:'pass parameter by reference' in Ruby?Ruby中的“通过引用传递参数”?
【发布时间】:2010-09-14 18:15:09
【问题描述】:

在 Ruby 中,是否可以通过引用传递具有值类型语义的参数(例如 Fixnum)? 我正在寻找类似于 C# 的 'ref' 关键字的东西。

例子:

def func(x) 
    x += 1
end

a = 5
func(a)  #this should be something like func(ref a)
puts a   #should read '6'

顺便说一句。我知道我可以使用:

a = func(a)

【问题讨论】:

    标签: ruby parameter-passing pass-by-reference


    【解决方案1】:

    您可以通过显式传入当前绑定来完成此操作:

    def func(x, bdg)
      eval "#{x} += 1", bdg
    end
    
    a = 5
    func(:a, binding)
    puts a # => 6
    

    【讨论】:

    • Ruby binding的文档
    • 这是一个可怕的问题:涉及各种错字、安全和丑陋的风险。最好使用某种包装器,并将“绑定”留给“撬”之类的东西。
    【解决方案2】:

    Ruby 根本不支持“按引用传递”。一切都是对象,对这些对象的引用总是按值传递。实际上,在您的示例中,您通过值传递了对 Fixnum 对象的引用副本。

    您的代码的问题是,x += 1 不会修改传递的 Fixnum 对象,而是创建一个全新的独立对象。

    我认为,Java 程序员会调用 Fixnum 对象不可变

    【讨论】:

    • 当变量和参数只能包含对对象的引用时,我没有得到 Ruby 不通过 ref 传递的东西。说引用是按值传递的,和说对象是按引用传递是一样的。
    • @Damien:不,不是。通过引用传递(例如,在 C++、C#、PHP、Perl 中)允许您将变量 assign 分配给变量,就像您在外部范围内分配给它一样。通过真正的引用传递,您在这里尝试做的事情是可能的;但不是通过引用值传递。
    • 你说得对,我正在再次阅读 Christoph 的回答和我的评论,但我不同意 2009 年的自我。嗯……
    【解决方案3】:

    在 Ruby 中,您不能通过引用传递参数。对于您的示例,您必须返回新值并将其分配给变量 a 或创建一个包含该值的新类并传递此类的实例。示例:

    class Container
    attr_accessor :value
     def initialize value
       @value = value
     end
    end
    
    def func(x)
      x.value += 1
    end
    
    a = Container.new(5)
    func(a)
    puts a.value
    

    【讨论】:

      【解决方案4】:

      您可以尝试以下技巧:

      def func(x) 
          x[0] += 1
      end
      
      a = [5]
      func(a)  #this should be something like func(ref a)
      puts a[0]   #should read '6'
      

      【讨论】:

      • 从技术上讲,这也是在写入时替换变量(和列表中的引用)。
      • @itarato a 和 x 在它们的整个生命周期中都指向同一个列表,因此没有替换任何变量,但是列表的第一个条目被更改为指向不同的数字。我喜欢这个技巧,因为使用列表感觉比包装类 .get/.set 方法更少的精神开销,但这确实意味着你需要记住用 [0] 取消引用它。
      【解决方案5】:

      http://ruby-doc.org/core-2.1.5/Fixnum.html

      Fixnum 对象具有直接价值。这意味着当他们被分配或 作为参数传递,传递的是实际对象,而不是引用 那个对象。

      还有Ruby is pass by value

      【讨论】:

        【解决方案6】:

        但是,复合对象(如哈希)似乎是通过引用传递的:

        fp = {}
        def changeit(par)
          par[:abc] = 'cde'
        end
        
        changeit(fp)
        
        p fp
        

        给予

        {:abc=>"cde"}
        

        【讨论】:

        • 哈希是按值传递的,但该值是对可变对象的引用。所以 fp 总是指向同一个哈希对象实例,但是 changeit 修改了它的内容。您可以通过打印 fp.object_id 和 par.object_id 来确认这一点。您不能仅通过为 par 分配不同的哈希值来影响 fp 的值——这是“通过引用传递”所允许的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-07
        • 1970-01-01
        • 1970-01-01
        • 2011-08-21
        • 2017-09-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多