像这样的逻辑的最佳Ruby习语

时间:2011-02-13 11:30:06

标签: ruby idioms

我在这里概述了两个功能。 js_funct是一种常见的js样式,test_funct是我尝试Ruby-ize它。

任何更好/替代/清洁/红宝石的处理方式?

@flipped_on = true

# assume my_funct is expensive
def my_funct
  'success'
end

def test_funct
  res = my_funct if @flipped_on
  res.length if res
end

def js_funct
  if @flipped_on
    res = my_funct
    if res
      return res.length
    end
  end
  return nil
end

p test_funct
p js_funct

编辑:

想想我可能在这里回答了我自己的问题。虽然需要很多思考才能解释这一点。

def test_funct
  res = my_funct and res.length if @flipped_on
end

3 个答案:

答案 0 :(得分:2)

这是一个常见的Ruby习惯用法,用于执行一次昂贵的计算并缓存结果:

def expensive_function
  @expensive_function ||= compute_expensive_function
end

这会导致compute_expensive_function只被调用一次,无论burn_function被调用多少次。

警告:因为这种技术依赖于短路或操作符,所以对于返回true / false(或truthy / falsy)的函数它将无法正常工作。为此,有promise gem

def initialize
  @expensive_function = promise {compute_expensive_function}
end

def do_something
  ...
  puts @expensive_function
  ...
end

承诺宝石比这里介绍的更通用。此外,它还附带一个future函数,它将结果缓存为promise,但也可以在单独的线程中进行计算,这样您就可以在昂贵的函数上获得先机:

def initialize
  @expensive_function = future {compute_expensive_function}
end

def do_something
  ...
  puts @expensive_function
  ...
end

答案 1 :(得分:0)

我必须说你的版本非常干净和可读,除了你实际上可以移除最后的返回nil 行,因为默认情况下,如果没有指定,ruby函数返回nil。

或者您也可以为此写一行:

def test_funct
  @flipped_on && (res = my_funct) && res.length || nil
end

如果返回false不是问题, ||零部分也可以删除。

编辑:您自己的版本更好: - >

答案 2 :(得分:0)

我不太确定js_funct应该做什么。其中res完全没用:

def js_funct
  if @flipped_on
    res = my_funct
    if res
      return res.length
    end
  end
  return nil
end

您可以说my_funct.length并获取函数my_funct返回的长度。

但似乎下面的事情让你感到困惑:在Ruby中,函数(我们称之为方法,因为它们总是属于一个对象)不是第一类对象。因此,您不能说res = my_funct,希望您将函数分配给变量,就像在JavaScript中一样。在Ruby中,该行首先执行 my_funct方法,并将其结果放入名为res的变量中。

如果您想检查方法是否已定义,您可以使用Object#respond_to?方法。

如果您希望将方法包装到对象中以便传递它,则应使用Object#method方法。但是在Ruby中,传递 blocks (闭包)更常见,而不是整个方法。事实上,每次使用mapeach或其他常见的Ruby方法时,您都会这样做。

如果您想了解如何在Ruby中编写特定任务,您应该说明该任务是什么。你的例子没有说明。