||= 是一个常见的 Ruby 习惯用法:它仅在尚未设置值时才分配值。效果和代码一样
if some_variable == nil
some_variable = some_value
end
或
some_variable= some_value unless some_variable
===,当没有被覆盖时,比较两个对象的身份。在Hash === args.last 的情况下,Hash(它是 Class 类型的对象)正在检查它是否与 args 数组中最后一项的类匹配。代码利用了 Class#=== 的实现强制检查比较对象的类这一明显事实。
反之则不行,例如:
a = [{}]
Hash === a.last #=> true
a.last === Hash #=> false
方法的尾随参数可以作为哈希的内容提供,而无需提供 {}
所以你可以这样做:
def hello(arg1, arg2, arg3)
puts [arg1.class, arg2.class, arg3.class].join(',')
end
hello 1,2,3 #=> Fixnum,Fixnum,Fixnum
hello :a, "b", :c => 1, :d => 99 #=> Symbol,String,Hash
它通常用于为函数提供可变长度的可选参数列表。
顺便说一句,您确定您准确地转录了原始代码吗?为了获得参数数组,您通常会在声明的参数中添加一个 *,否则 args 必须作为数组输入,而这会破坏对象。
def add_spec_path_to(*args) # now args is an array
args << {} unless Hash === args.last # if trailing arguments cannot be
# interpreted as a Hash, add an empty
# Hash here so that following code will
# not fail
args.last[:spec_path] ||= caller(0)[2] # Set the spec_path option if it's not
# already set
end
编辑:进一步扩展 *args 事情,试试这个:
def x(*args)
puts args.join(',')
puts args.map{|a| a.class }.join(',')
end
x 1,2,:a=>5,:b=>6
1,2,a5b6
Fixnum,Fixnum,Hash
... 使用 *args 会导致 args 作为数组呈现给方法。如果我不使用*,像这样,例如:
def y(args)
puts args.join(',')
puts args.map{|a| a.class }.join(',')
end
... 那么在我调用该方法之前 args 必须是一个数组,否则我将得到一个“ArgumentError:错误数量的参数”,但只有一件事传递。所以它必须看起来像这样:
y [1,2,{:c=>3,:d=>4}]
...使用 {} 显式创建的哈希。而且很丑。
以上所有测试均使用 MRI 1.8.6,顺便说一句。