Ruby 错误的省略空格导致的 Ambiguous Operator 问题

hellomac · 2018年05月19日 · 最后由 msg7086 回复于 2018年05月23日 · 1528 次阅读
p "4".to_i +3    # => 0 这个结果很费解,竟然不是 7
p "4".to_i + 3   # => 7
p 4 +3             # => 7
p 4 + 3            # => 7

如果不开终端确认,第一个结果我就搞错了。我知道这是错误的省略空格导致的歧义,可是为什么会得零? 尝试获取语法树的结果:

require 'parser/current'
# opt-in to most recent AST format:
Parser::Builders::Default.emit_lambda   = true
Parser::Builders::Default.emit_procarg0 = true
Parser::Builders::Default.emit_encoding = true
Parser::Builders::Default.emit_index    = true
pp Parser::CurrentRuby.parse('"4".to_i +3')
pp Parser::CurrentRuby.parse('"4".to_i + 3')
pp Parser::CurrentRuby.parse('"4".to_i +3').loc
pp Parser::CurrentRuby.parse('"4".to_i + 3').loc

输出为

s(:send,
  s(:str, "4"), :to_i,
  s(:int, 3))
s(:send,
  s(:send,
    s(:str, "4"), :to_i), :+,
  s(:int, 3))
#<Parser::Source::Map::Send:0x00007f9ff589c348
 @begin=nil,
 @dot=#<Parser::Source::Range (string) 3...4>,
 @end=nil,
 @expression=#<Parser::Source::Range (string) 0...11>,
 @node=s(:send,
  s(:str, "4"), :to_i,
  s(:int, 3)),
 @selector=#<Parser::Source::Range (string) 4...8>>
#<Parser::Source::Map::Send:0x00007f9ff78428c8
 @begin=nil,
 @dot=nil,
 @end=nil,
 @expression=#<Parser::Source::Range (string) 0...12>,
 @node=s(:send,
  s(:send,
    s(:str, "4"), :to_i), :+,
  s(:int, 3)),
 @selector=#<Parser::Source::Range (string) 9...10>>

没看出操作符是怎么丢失的,再底层一些:

require 'ripper'
pp Ripper.sexp '"4".to_i + 3'
pp Ripper.sexp '"4".to_i +3'

输出为:

[:program,
 [[:binary,
   [:call,
    [:string_literal, [:string_content, [:@tstring_content, "4", [1, 1]]]],
    :".",
    [:@ident, "to_i", [1, 4]]],
   :+,
   [:@int, "3", [1, 11]]]]]
[:program,
 [[:command_call,
   [:string_literal, [:string_content, [:@tstring_content, "4", [1, 1]]]],
   :".",
   [:@ident, "to_i", [1, 4]],
   [:args_add_block, [[:@int, "+3", [1, 9]]], false]]]]

仍然没看出为何会得零?

to_i(base=10) → integer click to toggle source Returns the result of interpreting leading characters in str as an integer base base (between 2 and 36). Extraneous characters past the end of a valid number are ignored. If there is not a valid number at the start of str, 0 is returned. This method never raises an exception when base is valid.

'4'.to_i(+3) = 0

😂 Ruby 统统都是对象,只能猜到是这样。至于为什么,你不说,我估计跟你一样

Ruby 编程语言


无关的,另外 kcptun 是你写的吗?你两头像一模一样(无意中看见的)

puma 回复

感谢解惑,kcptun 并非本人作品。另头像是本人,也仅在本站出没。

puma 回复

思维够敏捷呀 感觉这个都可以拿去当面试题了

.to_i(+3) 应该是很容易猜的。

foo (bar, baz) 这种调用方法也是很久之前就被废止了,要求括号与函数名之间不得有空格。其后对于 foo (1) + 2一律解释成 foo( (1) + 2 )

需要 登录 后方可回复, 如果你还没有账号请 注册新账号