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

How to pass by reference in Ruby?

提问人:David Wright 提问时间:8/29/2016 更新时间:8/29/2016 访问量:4507

问:

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

我写的类的相关部分如下所示。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 中有什么方法可以通过引用传递吗?如果没有,有没有其他方法可以解决这个问题?

Ruby 参数传递 传递

评论

0赞 David Wright 8/29/2016
@Ven 在我的测试应用程序中,目前有效。但我正在使用一个庞大且相当古老的框架。考虑到我可能无法在参数是否为对象之间做出选择,还会有另一种方法吗?
0赞 Ven 8/29/2016
无论如何,在 Ruby 中,一切都是一个对象
0赞 David Wright 8/29/2016
@Stefan 信号被映射到变量中。例如,我正在检查蜂鸣器是否以特定频率切换。状态是否嗡嗡作响存储在全局变量中。但是我还需要测量其他值的频率,这就是为什么我想避免直接从全局变量读取。
0赞 David Wright 8/29/2016
@Ven 好吧,在那种情况下,我真的没有选择使用对象,是吗?既然没有其他选择......
0赞 Stefan 8/29/2016
使用对象”和“一切都总是对象”在某种程度上是矛盾的。Ven 可能意味着你应该使用一个可变对象。

答:

10赞 Jörg W Mittag 8/29/2016 #1

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

a = 'foo'

def bar(b)
  b = 'bar'
end

bar(a)

a
# => 'foo'

但请注意,即使引用不能

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)
  :"#{a}bar"
end

c = bar(a)

c
# => :foobar

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

a = [:foo]

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

bar(a)

a
# => [:bar]

[这与上面的第二个示例确实是一回事。

但是,如果你不能改变任何东西,那么你就被困住了。

评论

0赞 Jörg W Mittag 8/29/2016
或者,你可以称之为“封装确实有效”。
0赞 David Wright 8/29/2016
怎么会这样?如果您无法控制数据的存储位置,我会说“工作”有点牵强。您期望如何在无法写入或读取某些地址的情况下访问控制器的寄存器?