Ruby方法带有默认值的参数哈希:如何DRY?

3

我有一个initialize方法,它接受一个哈希值来设置一些实例变量。基本上,这就是我想做的事情:

class Ad
  DEFAULT_PAGE = 'index'.freeze

  DEFAULT_CHANNEL = 'general'.freeze

  DEFAULT_AREA = 'general'.freeze

  attr_accessor :page, :area, :channel

  def initialize args={}
    @page = args[:page] || DEFAULT_PAGE
    @area = args[:area] || DEFAULT_AREA
    @channel = args[:channel] || DEFAULT_CHANNEL
  end

  # ...
end

我看到一个技巧可以允许动态设置实例变量,但我不确定如何同时包含默认值...

  def initialize args={}
    args.each do |attr,val|
      instance_variable_set("@#{attr}", val) unless val.nil?
    end
  end

我能动态地引用常量吗?或者有更好的方法来完成这种事情吗?

......我也意识到attr_accessor变量可以单独设置。但我只想这样做。 :)


在“initialize”定义的第三行中,“v”是什么? - sawa
本意是放置val...感谢指出。 - Erik J
1
可能是在Ruby中使用带有默认值的选项哈希作为参数的好方法是什么?的重复。但不要感到难过 - 这是一个寻找重复的努力! - Andrew Grimm
谢谢,我确实尝试找到重复的内容,但没有找到。 - Erik J
2个回答

10

这个方法只会在defaults哈希表中存在的情况下创建实例变量,以免意外地创建/覆盖其他实例变量。

我猜你想说的是unless val.nil?吧:

def initialize(args={})
  defaults = {
    :page    => DEFAULT_PAGE,
    :area    => DEFAULT_AREA,
    :channel => DEFAULT_CHANNEL
  }.merge(args).each do |attr, val|
    instance_variable_set("@#{attr}", val) if defaults.has_key?(attr) && (not val.nil?)
  end if args
end

是的,我确实想要放置 unless val.nil?... 谢谢,我也不想暴露任何其他实例变量被设置的可能性。谢谢! - Erik J
2
@Jorge:如果defaults包含一个布尔赋值,其值为false,那么实例变量不会被创建;我认为你代码的最后一部分应该写成:...if defaults.has_key?(attr) && (not val.nil?) - zaiste

1

试试这个:

  def initialize args={}
    defaults = {
      :page    => DEFAULT_AREA, 
      :area    => DEFAULT_AREA, 
      :channel => DEFAULT_CHANNEL
    }
    args.reverse_merge(defaults).each do |attr,val|
      instance_variable_set("@#{attr}", val) unless val.nil?
    end
  end

如果我没记错的话,reverse_merge 是在 ActiveSupport 中实现的,因此,在没有导入 ActiveSupport 的情况下,它将不会在原始的 Ruby 中可用。 - yihangho
v.nil? should be val.nil? - Andrew K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接