Ruby 传递散列而不是方法参数
我看到在Ruby(通常是动态类型语言)中,一种非常常见的做法是传递散列,而不是声明具体的方法参数。例如,与其声明带有参数的方法并像这样调用它,不如:Ruby 传递散列而不是方法参数,ruby,oop,coding-style,Ruby,Oop,Coding Style,我看到在Ruby(通常是动态类型语言)中,一种非常常见的做法是传递散列,而不是声明具体的方法参数。例如,与其声明带有参数的方法并像这样调用它,不如: def my_method(width, height, show_border) my_method(400, 50, false) 您可以这样做: def my_method(options) my_method({"width" => 400, "height" => 50, "show_border" => false}
def my_method(width, height, show_border)
my_method(400, 50, false)
您可以这样做:
def my_method(options)
my_method({"width" => 400, "height" => 50, "show_border" => false})
我想知道你对这件事的看法。这是一个好的做法还是一个坏的做法,我们应该做还是不做?在什么情况下使用这种做法是有效的,在什么情况下可能是危险的?这是一种良好的做法。您不需要考虑方法签名和参数的顺序。另一个优点是,您可以很容易地忽略不想输入的参数。
您可以看看ExtJS框架,因为它广泛使用这种类型的参数传递。我认为当有多个参数或多个可选参数时,这种参数传递方法更为清晰。它本质上使方法调用明显地自文档化。在Ruby中,使用哈希而不是形式参数是不常见的做法。 我认为这与将散列作为参数传递的常见模式相混淆,因为该参数可以接受许多值,例如在GUI工具包中设置窗口的属性 如果方法或函数有许多参数,则显式声明并传递它们。您得到的好处是,解释器将检查您是否已传递了所有参数
不要滥用语言功能,知道什么时候使用它,什么时候不使用它。Ruby有隐式散列参数,所以您也可以编写
def my_method(options = {})
my_method(:width => 400, :height => 50, :show_border => false)
通过Ruby 1.9和新的哈希语法,它可以
my_method( width: 400, height: 50, show_border: false )
当一个函数包含3-4个以上的参数时,不计算相应的位置,就很容易看出哪个是什么。这是一种折衷。您失去了一些清晰性(我如何知道要传递什么参数)和检查(我传递了正确数量的参数吗?)并获得了灵活性(该方法可以默认它没有接收到的参数,我们可以部署一个新版本,使用更多参数,并且不破坏现有代码) 您可以将此问题视为更大的强/弱类型讨论的一部分。请看这里的博客。我在C和C++中使用了这种风格,在这里我想支持相当灵活的参数传递。可以说,带有一些查询参数的标准HTTP GET正是这种风格
如果您选择hash appraoch,我会说您需要确保您的测试非常好,参数名称拼写错误的问题只会在运行时出现。这两种方法都有各自的优点和缺点,当使用选项散列替换标准参数时,定义方法的代码将变得不清晰,但每当使用该方法时,就会变得清晰,因为使用选项散列创建的伪命名参数
我的一般规则是,如果一个方法有很多参数(超过3个或4个),或者有很多可选参数,那么就使用选项散列,否则就使用标准参数。但是,在使用选项哈希时,务必在方法定义中包含一条注释,说明可能的参数。如果您:
@选项
标记指定选项:
##
# Create a box.
#
# @param [Hash] options The options hash.
# @option options [Numeric] :width The width of the box.
# @option options [Numeric] :height The height of the box.
# @option options [Boolean] :show_border (false) Whether to show a
# border or not.
def create_box(options={})
options[:show_border] ||= false
end
但在这个具体的例子中,参数非常少且简单,所以我想我应该这样做:
##
# Create a box.
#
# @param [Numeric] width The width of the box.
# @param [Numeric] height The height of the box.
# @param [Boolean] show_border Whether to show a border or not.
def create_box(width, height, show_border=false)
end
我确信没有人使用动态语言关心这个问题,但是想想当你开始向函数传递散列时,你的程序将会受到的性能损失 解释器可能足够聪明,可以创建一个静态常量散列对象,并且只通过指针引用它,如果代码使用的是散列,所有成员都是源代码文本 但是,如果这些成员中有任何一个是变量,那么每次调用哈希时都必须重新构造它 我已经做了一些Perl优化,这种事情在内部代码循环中变得很明显
函数参数的性能要好得多。使用
散列作为参数的好处在于消除了对参数数量和顺序的依赖
实际上,这意味着您以后可以灵活地重构/更改方法,而不会破坏与客户机代码的兼容性(这在构建库时非常好,因为您实际上无法更改客户机代码)
(如果你对Ruby中的软件设计感兴趣,Sandy Metz是一本很棒的书)一般来说,我们应该始终使用标准参数,除非这是不可能的。在不必使用选项的情况下使用选项是不好的做法。标准参数是清晰的,并且是自我记录的(如果命名正确的话)
使用选项的一个(可能也是唯一的)原因是函数接收的参数不进行处理,而只是传递给另一个函数
下面是一个例子,说明:
def myfactory(otype, *args)
if otype == "obj1"
myobj1(*args)
elsif otype == "obj2"
myobj2(*args)
else
puts("unknown object")
end
end
def myobj1(arg11)
puts("this is myobj1 #{arg11}")
end
def myobj2(arg21, arg22)
puts("this is myobj2 #{arg21} #{arg22}")
end
在本例中,“myfactory”甚至不知道“myobj1”或“myobj2”所需的参数myfactory只将参数传递给“myobj1”和“myobj2”,检查和处理它们是它们的责任。哈希对于传递多个可选参数特别有用。例如,我使用散列来初始化参数为可选的类
例子
如果您需要可变数量的参数,只需使用def method(*args)
,散列无法解决特定的问题感谢您指出了潜在的混淆。我真的在想这个案子
class Example
def initialize(args = {})
@code
code = args[:code] # No error but you have no control of the variable initialization. the default value is supplied by Hash
@code = args.fetch(:code) # returns IndexError exception if the argument wasn't passed. And the program stops
# Handling the execption
begin
@code = args.fetch(:code)
rescue
@code = 0
end
end