简体   繁体   English

红宝石:大量初始化实例变量

[英]ruby: mass initializing instance variables

Is there an easy way to bulk assign instance variables 是否有一种简单的方法来批量分配实例变量

  def initialize(title: nil, label_left: nil, label_right: nil, color_set: nil)
    @title = title
    @label_left = label_left
    @label_right = label_right
    @color_set = color_set
  end

Can I loop/iterate through the initialize arguments and assign automatically? 我可以循环/迭代初始化参数并自动分配吗?

If you want specific variables, then not really. 如果您想要特定的变量,那不是真的。 Using reflection here, even if it was available, would be trouble. 即使可以使用反射,在这里使用反射也会很麻烦。

What you've got here is the most trivial case. 您在这里遇到的是最琐碎的情况。 Often you'll see code that looks more like this: 通常,您会看到看起来像这样的代码:

def initialize(title: nil, label: nil, label_width: nil, color_set: nil)
  @title = title.to_s
  @label = label_left.to_s
  @label_width = label_width.to_i
  @color_set = MyRGBConverter.to_rgb(color_set)
end

The initializer is a place where you can do any necessary conversion and validation. 初始化程序是您可以进行任何必要的转换和验证的地方。 If some of those arguments are required to be certain values you'll have tests for that, raise an exception on an error and so forth. 如果要求其中某些参数为某些值,则将对此进行测试,并针对错误raise异常,依此类推。 The repetitive code you have here in the minimal case often gets expanded and augmented on so there's no general purpose solution possible. 在最小的情况下,您在此处具有的重复代码通常会进行扩展和扩充,因此不可能有通用的解决方案。

That leads to code like this: 导致这样的代码:

def initialize(title: nil, label: nil, label_width: nil, color_set: nil)
  @title = title.to_s
  unless (@title.match(/\S/))
    raise "Title not specified"
  end

  @label = label_left.to_s
  unless (@label.match(/\A\w+\z/))
    raise "Invalid label #{@label.inspect}"
  end

  @label_width = label_width.to_i
  if (@label_width <= 0)
    raise "Label width must be > 0, #{@label_width} specified."
  end

  @color_set = MyRGBConverter.to_rgb(color_set)
end

If you really don't care about which arguments you're taking in then you can do this in Ruby 2.3 with the new keyword-arguments specifier ** : 如果您真的不关心要使用的参数,则可以在Ruby 2.3中使用新的关键字参数说明符**

def initialize(**options)
  options.each do |key, value|
    instance_variable_set("@#{key}", value)
  end
end

Note that's potentially dangerous if those values are user supplied, so you might want to white-list them somehow: 请注意,如果这些值是用户提供的,则可能存在危险,因此您可能希望以某种方式将它们列入白名单:

VALID_OPTIONS = [ :title, :label_left, :label_right, :color_set ]

def initialize(**options)
  options.each do |key, value|
    raise "Unknown option #{key.inspect}" unless (VALID_OPTIONS.include?(key))

    instance_variable_set("@#{key}", value)
  end
end

Where you're seeing a lot of these arguments being passed in on a regular basis you might want to evaluate if creating some kind of struct-like object and passing that through might be a better plan. 在经常看到大量此类参数传递的地方,您可能需要评估是否创建某种类似于struct的对象并将其传递通过是更好的计划。 It depends on how your code works. 这取决于代码的工作方式。

@tadman provided already an excellent answer to this, but here is one more: If you are willing to dispense with named parameters, you could do it like this: @tadman已经提供了一个很好的答案,但是这里还有一个:如果您不想使用命名参数,则可以这样做:

def initialize(*args)
  @title, @label_left, @label_right, @color_set, *nada = args
  fail "Too many arguments" unless nada.empty?
end 

[UPDATE: Fixed the code, according to the comment given by @sawa]. [更新:根据@sawa给出的注释修复了代码]。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM