如何在 Ruby 中通过引用传递?

Posted

技术标签:

【中文标题】如何在 Ruby 中通过引用传递?【英文标题】:How to pass by reference in Ruby? 【发布时间】:2017-01-05 08:19:14 【问题描述】:

目前我正在 Ruby 中开发一个Watcher 类,除其他外,它能够找到切换信号的周期持续时间。这通常相当简单,但我面临的一个问题是显然 Ruby 按值传递所有参数。 在网上研究时,我发现许多关于“按值传递”和“按引用传递”实际上是什么的不同讨论,但没有实际的“如何”。来自 C/C++ 背景,对我来说,这是编程/脚本语言的重要组成部分。

我编写的类的相关部分如下所示。 Watcher::watchToggling() 方法是我遇到问题的方法。作为参数,aVariable 应该是我正在测量周期持续时间的值的参考。

class Watcher
  @done
  @timePeriod

  def reset()
    @done = false;
    @timePeriod = nil;
  end

  def watchToggling(aVariable, aTimeout=nil)
    oldState = aVariable;
    oldTime = 0;
    newTime = 0;

    timeout(aTimeout)do
      while(!@done)
        newState = aVariable;
        if(newState != oldState)
          if(newState == 1)
            # rising edge
            if(oldTime != 0)
              # there was already a rising edge before,
              # so we can calculate the period
              newTime = Time.now();
              @timePeriod = newTime - oldTime;
              @done = true;
            else
              # if there was no previous rising edge,
              # set the time of this one
              oldTime = Time.now();
            end
          end
          oldState = newState;
        end
      end
    end

    puts("Watcher: done.")
  end

  def isDone()
    return @done;
  end

  def getTimePeriod()
    return @timePeriod;
  end
end

ruby 有什么方法可以通过引用传递吗?如果没有,是否有替代方案可以解决这个问题?

【问题讨论】:

你的信号是如何实现的,特别是切换? @Ven 在我现在工作的测试应用程序中。但我正在使用一个庞大且相当古老的框架。考虑到我可能无法在参数是否为对象之间进行选择,是否有另一种方法? 在 Ruby 中一切都是对象 @Stefan 信号被映射到变量中。例如,我正在检查蜂鸣器是否以特定频率切换。是否蜂鸣的状态存储在全局变量中。但是我还需要测量其他值的频率,这就是为什么我要避免直接从全局变量中读取。 @Ven 那么在那种情况下,我真的没有选择使用对象,不是吗?既然没有其他选择... 【参考方案1】:

Ruby 是严格按值传递的,这意味着调用者范围内的引用是不可变的。显然它们在范围内是可变的,因为您毕竟可以分配给它们,但它们不会改变调用者的范围。

a = 'foo'

def bar(b)
  b = 'bar'
end

bar(a)

a
# => 'foo'

但是请注意,即使引用不能,object 也可以被改变:

a = 'foo'

def bar(b)
  b << 'bar' # the only change: mutate the object instead of the reference
  b = 'baz'
end

bar(a)

a
# => 'foobar'

如果您传递的对象也是不可变的,那么您无能为力。 Ruby 中唯一的变异可能性是改变引用(通过赋值)或要求对象改变自身(通过调用它的方法)。

您可以从您的方法返回一个更新的值,并让调用者将其分配给引用:

a = :foo

def bar(b)
  :"#abar"
end

c = bar(a)

c
# => :foobar

或者您可以将不可变对象包装在一个可变对象中并改变该可变包装器:

a = [:foo]

def bar(b)
  b[0] = :bar
end

bar(a)

a
# => [:bar]

[这实际上和上面的第二个例子是一样的。]

但如果你不能改变任何东西,那么你就会陷入困境。

【讨论】:

或者,你可以称之为“封装确实有效”。 怎么样?如果您无法控制数据的存储位置,我会说“工作”有点牵强。如果无法写入或读取某些地址,您会如何访问控制器的寄存器?

以上是关于如何在 Ruby 中通过引用传递?的主要内容,如果未能解决你的问题,请参考以下文章

如何在php中通过引用传递无限参数[重复]

在 C++ 中通过引用/值传递

如何访问在 C++ 中通过引用传递的列表/向量的元素

在 C 中通过引用传递时会发生啥?

如何通过在 PHP 中通过引用传递变量来存储变量?

在python中通过引用传递引用