ruby - 在 Ruby 中的 `do..end` 块和花括号中不同的 `puts` 行为
问题描述
我是一名经验丰富的开发人员,但也是一名 Ruby 新手。我正在阅读这个线程do..end vs curly brackets for blocks in Ruby并学习了一些关于何时使用大括号以及何时使用do .. end
块的好东西。其中一个技巧是do .. end
在您关注副作用时使用,而当您担心返回值时使用 {}。因此,我正在尝试使用枚举器教程中的一些示例:
irb(main):001:0> my_array = [1, 2]
=> [1, 2]
irb(main):002:0> my_array.each {|num| num *= 2; puts "The new number is #{num}."}
The new number is 2.
The new number is 4.
=> [1, 2]
irb(main):003:0> my_array.each do |num| num *= 2; puts "The new number is #{num}." end
The new number is 2.
The new number is 4.
=> [1, 2]
不挂断。我认为该do..end
块返回一个枚举器对象?它看起来像一个数组。让我们检查:
irb(main):004:0> puts my_array.each {|num| num *= 2; puts "The new number is #{num}."}
The new number is 2.
The new number is 4.
1
2
=> nil
irb(main):005:0> puts my_array.each do |num| num *= 2; puts "The new number is #{num}." end
#<Enumerator:0x000055967e53ac40>
=> nil
好的,它是一个枚举器。puts
但是第 005 行循环中的调用输出发生了什么?{} 具有预期的副作用,但没有do..end
阻止,这似乎违反了该经验法则。
我的"The new number is #{num}."
琴弦怎么了?
解决方案
do...end
并且{}
对于方法块是 100% 语义等效的。它们唯一的区别是它们的解析优先级,因此它们的评估方式不同
要真正理解这种差异,首先要了解几件事。
Ruby 允许您在没有括号的情况下调用方法:
my_object.my_method my_arg
# so my_arg could actually be a method! Let's put parens in to show that:
my_object.my_method(my_arg())
Ruby 中的块是方法参数——一种传入闭包的语法(在父作用域中起作用的特殊关键字除外)。以下两个块是等效的:
[1, 2, 3].map { |x| 2 * x }
# split out into two lines
double = ->(x) { 2 * x } # shorthand for `lambda { |x| 2 * x }`
[1, 2, 3].map(&double)
好的,知道了这一切,让我们来看看{}
和之间的区别do...end
:
my_method [1, 2, 3].map { |x| 2 * x }
my_method([1, 2, 3].map { |x| 2 * x }) # parses like this
my_method [1, 2, 3].map do |x| 2 * x end
my_method([1, 2, 3].map) do |x| 2 * x end # parses like this
my_method([1, 2, 3].map) { |x| 2 * x } # in other words
{}
的优先级高于do...end
, 立即与其左侧的方法关联。do...end
具有较低的优先级,并且将与my_method
,它被传递[1, 2, 3].map
并且块作为参数关联。
这意味着,您在上面所做的是:
puts(my_array.each) { |num| num *= 2; puts "The new number is #{num}." }
您已经传入puts
,my_array.each
它是一个枚举器和一个块,并且puts
对传入其中的块不做任何事情,默认情况下所有方法也是如此。
推荐阅读
- azure-resource-manager - Azure 资源图查询 | 获取 VM 许可证权益类型
- sql-server - ZK 指纹模板要保存到 SQL Server 数据库中的表 TEMPLATE (C#)
- sql-server - 如何解决连接到 SQL Server 的“不受信任的域”身份验证错误?
- apache-spark - Redshift COPY 无效数字,值 '"',位置 0,类型:Long
- ruby-on-rails - Rails DELETE 路由无法正常工作/未调用控制器功能
- java - 简单字符串的 Gson 转换失败并出现异常
- reactjs - React - Redux 调度程序未映射
- vim - VIM:如何过滤 COC.nvim 上的诊断信息?
- postgresql - Golang 结构的 Postgres 数组
- php - DateTimeZone 只处理一个方向的偏移量