有人可以解释一下这段Ruby代码:

def add_spec_path_to(args) # :nodoc:
  args << {} unless Hash === args.last
  args.last[:spec_path] ||= caller(0)[2]
end

我已经看到<<运算符用于连接字符串或其他语言中的按位运算符,但是有人可以在这种情况下对其进行解释。是将空白的lamda附加到args上还是我完全错了?

我也可以看到它像这样使用:
before_parts(*args) << block
Hash是关键字吗?

我也不确定||=运算符在说什么。

至于caller(0)[2]是什么,我也同样处于黑暗之中。

最佳答案

|| =是常见的Ruby习惯用法:仅在尚未设置值时才分配该值。效果与类似的代码相同

if some_variable == nil
   some_variable = some_value
end

或者
some_variable= some_value unless some_variable

===,当不被覆盖时,比较两个对象的身份。对于Hash === args.last,哈希(它是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(顺便说一句)进行了测试。

关于Ruby代码说明,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/609612/

10-15 07:32