在方法调用中是否存在memoization约定?

时间:2012-10-10 11:38:31

标签: ruby coding-style memoization

我想避免在方法调用中重新评估值。直到现在,我这样做:

def some_method
  @some_method ||= begin
    # lot's of code
  end
end

但它最终很难看。在某些代码中,我看到如下内容:

def some_method
  @some_method ||= some_method!
end

private

def some_method!
  # lot's of code
end

我最后不喜欢爆炸(!)所以我想出了这个:

def some_method
  @some_method ||= _some_method
end

private

def _some_method
  # lot's of code
end
  • 前缀是一个好的约定吗?
  • 对于记忆/非记忆对方法,还有其他约定吗?
  • 是否有一些惯例来记住多行方法?

6 个答案:

答案 0 :(得分:24)

我会这样做:

def filesize
  @filesize ||= calculate_filesize
end

private

def calculate_filesize
  # ...
end

所以我只是以不同的方式命名方法,因为我觉得它更有意义。

答案 1 :(得分:9)

我认为还有一种方式,更多Java风格。

首先,您应该实施注释,例如“Java-style annotations in Ruby”和“How to simulate Java-like annotations in Ruby?”。

然后你应该添加像_cacheable这样的注释,它会告诉它应该返回实例变量的方法,如果它是null,它应该通过调用方法来计算它,所以你的代码会更清楚:

_cacheable
def some_method
   # do_some_work
end

答案 2 :(得分:5)

我使用memoist gem,它可以让您轻松记住方法,而无需更改原始方法或创建两种方法。

例如,不是使用两个方法file_sizecalculate_file_size,而是必须使用实例变量自己实现memoization:

def file_size
  @file_size ||= calculate_file_size
end

def calculate_file_size
  # code to calculate the file size
end

你可以这样做:

def file_size
  # code to calculate the file size
end
memoize :file_size

每个memoized函数都有一种刷新现有值的方法。

object.file_size       # returns the memoized value
object.file_size(true) # bypasses the memoized value and rememoizes it

所以调用object.file_size(true)相当于调用object.calculate_file_size ...

答案 3 :(得分:3)

我通常根据你的第一个例子使用begin, end,但如果有更多的代码,我只看看变量是否存在,不需要为此创建另一个方法。

def some_method
  return @some_method if @some_method
  # lot's of code
  @some_method
end

答案 4 :(得分:2)

我也不喜欢爆炸。我用

def some_method 
  @some_method_memo ||= some_method_eval 
end 

private 

def some_method_eval
  # lot's of code 
end 

此处evalevaluation的简写。我喜欢这种读取的方式,并且它使公共界面简洁。

我鄙视依赖下划线作为区别标记的惯例:它们都容易出错,需要我记住YAMC(又一个毫无意义的惯例)。 Ada语言专为安全关键型应用程序而设计,不允许使用前导,尾随或多个下划线。好主意。

答案 5 :(得分:0)

我通常会在Agis回答或

中执行此操作
def filesize() @filesize ||=
  calculate_filesize
end

顺便说一句:

我经常使用这种记忆技术:

def filesize() @_memo[:filesize] ||=
  calculate_filesize
end

这将允许您稍后使用一个简单的@_memo.clear清除所有已记忆的变量。应该像这样Hash.new { |h, k| h[k] = Hash.new }初始化@_memo变量。 它为您提供了许多使用ActiveSupport :: Memoize以及might be much slower的类似元编程技术的尝试。