Ruby中puts与sort代码块结合排序失效的原因咨询
问题
我需要对包含日期的日志文件逐行排序。以下代码无法正确排序:
puts readlines.sort do |a, b| a[/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/, 1] <=> b[/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/, 1] end
但添加括号后的代码可以正确排序:
puts (readlines.sort do |a, b| a[/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/, 1] <=> b[/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/, 1] end)
使用的Ruby版本:
$ ruby -v ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [x86_64-linux]
请问出现这种差异的原因是什么?
原因分析
这是Ruby的方法调用优先级和块绑定规则导致的:
- 写
puts readlines.sort do ... end时,Ruby会把do...end块绑定到最近的方法——也就是puts,而非sort。实际执行逻辑是先调用readlines.sort(用默认的字符串字典序排序,完全没用到你定义的块),再把结果传给puts,同时把块传给puts(但puts不会使用这个块),所以排序结果不符合预期。 - 加上括号
(readlines.sort do ... end)后,括号明确限定了sort的调用范围,do...end块会被正确绑定到sort,让sort按照你写的日期比较逻辑排序,之后再把排序后的数组传给puts,就能得到正确结果。
另外补充个小技巧:用{}代替do...end块也能解决问题,因为{}的绑定优先级更高,会优先绑定到sort,示例如下:
puts readlines.sort { |a, b| a[/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/, 1] <=> b[/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/, 1] }
内容的提问来源于stack exchange,提问作者zinnia
相关产品推荐
相关产品推荐

