您的代码中没有哈希值。您正在查看的是一个块,它是一种匿名函数。 Ruby 有两种不同的块语法。这段代码:
before_save { self.email = email.downcase }
...等价于这段代码:
before_save do
self.email = email.downcase
end
一般来说,大括号用于单行,do ... end 用于多行。无论哪种情况,您所做的是定义代码“块”,然后将其作为参数传递给before_save 方法。这允许 Rails 将该代码块存储在变量中并稍后执行,或者将代码传递给其他方法。上面两个例子在很大程度上等价于这个:
my_block = proc do
self.email = email.downcase
end
before_save(&my_block)
块参数是特殊的。一个方法只能有一个块参数,并且它必须是最后一个参数。在最后一段代码中,我使用了proc(Proc.new 的快捷方式)实际上将块保存到变量,然后将该变量作为参数传递给before_save。 & 告诉 Ruby 它应该将该 Proc 视为 before_save 的块参数。
不过,有一些语法陷阱会出现在块中。例如,这是有效的:
[ "two", "three" ].reduce "one" do |memo, item|
memo << item
end
# => "onetwothree"
但这不是:
[ "two", "three" ].reduce "one" {|memo, item| memo << item }
# => SyntaxError: unexpected '{', expecting end-of-input
当你使用花括号语法并有参数时(如上面的"one"),你必须使用括号:
[ "two", "three" ].reduce("one") {|memo, item| memo << item }
# => "onetwothree"
除了块和 Procs,Ruby 有一种特殊的 Proc,称为 lambda。你会在一些 Rails 文档中看到 lambda,它们看起来像这样:
scope :published, -> { where(published: true) }
这是一个捷径:
scope :published, lambda { where(published: true) }
# ...or...
scope :published, lambda do
where(published: true)
end
...这些都等价于这个:
my_lambda = ->{ where(published: true) }
scope :published, my_lambda
请注意,第二行的my_lambda 之前没有&。这是因为 Rails 的开发人员选择让 scope 将 lambda 作为常规参数——而不是它的块参数——我认为,大多数情况下,它不必是最后一个参数。
blocks、procs 和 lambdas 之间的区别超出了这个答案的范围,有时甚至是微妙的,但这是很好的知识。我推荐这篇文章以获取更多信息:https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/18-blocks/lessons/64-blocks-procs-lambdas