ruby-on-rails Rails方法参数调用约定问题

dgtucam1  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(130)

我有下面的方法有很多参数。我已经将这个方法从参数列表转换为哈希,以避免与默认参数混淆。

def foo_bar(options = {})
    Rails.logger.info("Got params #{options.inspect}")

    good_name = options[:foo1]
    another_param = options[:foo2]
    yet_another = options[:foo3] || "yes"
    still_one = options[:foo3]
    valid_name = options[:foo4]
    easy_name = options[:foo5]
    mode = options[:foo6]
..

字符串
调用这个方法现在很容易,只使用上下文中必需的参数,这很好

foo_bar(foo1: my_foo1, foo3: my_foo3, foo6: my_mode)


但我的问题是,由于Rails通常是非常直观的语言,在那里你有很多快捷方式和方法来做事情,如何使这个方法的参数签名更清楚,

  • 我不需要从hash中提取参数,它们会自动分配给correcting local var,而没有那些“额外”的行,现在分配是从选项hash中进行的。
  • 没有一长串带有默认值的参数

我想避免这种情况,因为当调用这个方法时,我不能自由地选择我想赋值给哪个参数。而且调用也不清楚哪个参数是哪个参数,因为它们不是通过名称引用的,而是通过值和顺序引用的。

def foo_bar(good_name, another_param = nil, yet_another = "yes", still_one = "xx", valid_name = nil, easy_name = nil, foo6 = "std")


方法重载在这里不起作用,也试过了。这不像在C#或Java中实现。
我试过:方法重载参数作为散列参数“正常的方式”

hujrc8aj

hujrc8aj1#

首先,声明方法的现代方法是使用关键字参数而不是哈希作为位置参数。

def foo_bar(**options)
  # ...
end

字符串
位置参数方法的一个问题是,你实际上可以传递不是散列的输入,它会在方法内部爆炸,而不是得到一个参数错误,它会立即告诉你什么是错的。
**是一个双splat,意味着我们正在吸收传递给该方法的任何关键字参数。
处理默认值的方法有很多种。如果你不想在方法定义中显式列出它们(def foo(bar: :Baz, ...)),你可以使用一个私有方法来生成默认选项:

class Foo
  def bar(**kwargs)
    options = kwargs.reverse_merge(default_options)
    # ...
  end

  private

  def default_options
    { 
      a: 1,
      b: 2
    }
  end
end


这使得子类可以覆盖方法,并且在Rails代码库中随处可见。
reverse_merge来自ActiveSupport,你可以在普通Ruby中对merge做同样的事情,但顺序相反。
我不需要从hash中提取参数,它们会自动分配给correcting local var。
这种模式通常称为质量分配:

class Thing
  attr_accessor :foo
  attr_accessor :bar

  def initialize(**attributes)
    attributes.each do |key, value|
      send("#{key}=", value)
    end 
  end 
end 

Thing.new(foo: "a", bar: "b")


对于传递给方法的每个关键字参数,我们尝试调用一个与键同名的setter方法。虽然您可以直接调用instance_variable_set并设置Ivars,但这不允许您控制可以分配什么以及如何分配。
在Rails中,你可以从ActiveModel::AttributeAssignment的模型中免费获得它,如果需要,它可以混合到任何类中。

相关问题