用于通过参考传递计数器的优选红宝石成语

时间:2014-11-21 20:38:18

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

我有一个长期运行的迭代方法,根据我无法控制的外部因素容易出错。我想在调用者的范围内成功完成迭代计数,以便在方法爆炸时,调用者可以使用成功完成的迭代次数作为其错误处理和报告功能的一部分。由于ruby是严格按值传递的(不需要争论这个,真的),我的选择似乎仅限于传递一个计数器对象(它看起来太基本不值得拥有自己的对象)或一个人为的计数器数组,例如:

counter = [0]
begin
    LongRunningStuff.error_prone_iterations(counter)
    puts "success! completed #{counter[0]} iterations"
rescue
    puts "failed! completed #{counter[0]} iterations"
end

这感觉很糟糕(充其量),最糟糕的是彻头彻尾的愚蠢。对于某些更具红宝石色彩的东西的任何建议?

1 个答案:

答案 0 :(得分:3)

如果Ruby中有两个规则,那么所有都是一个对象,每个变量就像一个对象的引用。这看起来有点奇怪,但实际上非常一致。在混合基元和对象,引用和值的其他语言中,通常会有更多的混淆。

为什么不创建一个上下文对象并将其传递给而不是一个没有内在含义的笨重数组呢?例如:

context = {
  counter: 0
}

SomeModule.method_call(context)
puts context[:counter]

你甚至可以使用像OpenStruct这样的东西来整理一下:

require 'openstruct'
context = OpenStruct.new(counter: 0)

SomeModule.method_call(context)

puts context.counter

更多" Ruby"这样做的方法是创建一个上下文类,为你正在做的事情提供更多的语义含义:

class CounterContext
  attr_reader :counter

  def initialize
    @counter = 0
  end

  def count!
    @counter += 1
  end
end

通过这种方式,您可以对一些轻量级抽象进行分层,并使您的代码更具可读性。它还意味着使用像count!这样的方法,如果你想找出谁触发那个方法而不是试图追踪计数器增加的位置,你可以很容易地存入一些调试代码。