我知道在 puts
解析之前整行被解析并且变量的值被设置如下:
def get_value
42
end
if value = get_value
puts value
end
# => 42
我得到了以下结果,这正是我所期望的:
#p = "Im totally a string" # <--Commented.
puts "Am i a string? #{p}" if p = "Im a confused string"
# => "Am i a string? "
然而,这很奇怪。在单行代码之前声明 p
会以一种意想不到的方式改变输出:
p = "foo" # <--Un-commented.
puts "Am i a string? #{p}" if p = "Im a confused string"
# => "Am i a string? Im a confused string"
p
是一个FixNum
,不是下面的String
:
p = 1
puts "Am i a string? #{p}" if p = "Im a confused string"
# => "Am i a string? Im a confused string"
这是怎么回事?如果一开始并不明显,第二个代码块说明了 "Im a confused string"
是如何插入失败的。但是,在第三个示例中,简单地声明 p
(类型不可知)会导致插入 "Im a confused string"
我认为这个问题与这些问题不同但相似:
最佳答案
TLDR:不幸的是,您的示例存在缺陷,因为您为变量选择的名称与核心 ruby 中的现有方法冲突。
正如@SteveTurczyn 几分钟前提到的,如果变量在条件行之前是未知的,它将被解释为方法调用。
让我们探索一些机器代码,好吗?重要行已注释。
puts "Am i a string? #{myvar}" if myvar = "Im a confused string"
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1)
[ 2] myvar
0000 trace 1 ( 2)
0002 putstring "Im a confused string"
0004 dup
0005 setlocal_OP__WC__0 2
0007 branchunless 22
0009 putself
0010 putobject "Am i a string? "
0012 putself
0013 opt_send_simple <callinfo!mid:myvar, argc:0, FCALL|VCALL|ARGS_SKIP> # call method myvar
0015 tostring
0016 concatstrings 2
0018 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0020 leave
0021 pop
0022 putnil
0023 leave
当变量被预先声明时
myvar = "Im totally a string"
puts "Am i a string? #{myvar}" if myvar = "Im a confused string"
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1)
[ 2] myvar
0000 trace 1 ( 1)
0002 putstring "Im totally a string"
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 putstring "Im a confused string"
0010 dup
0011 setlocal_OP__WC__0 2
0013 branchunless 27
0015 putself
0016 putobject "Am i a string? "
0018 getlocal_OP__WC__0 2 # Read variable value
0020 tostring
0021 concatstrings 2
0023 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0025 leave
0026 pop
0027 putnil
0028 leave
现在,您的代码的问题是 p
是一个存在 的方法。如果您不知道,p foo
等同于 puts foo.inspect
。与 puts
类似,它接受灵活数量的参数(甚至零个参数)并返回 nil
。
puts "Am i a string? #{p}" if p = "Im a confused string"
^ call method `p` here
但是
p = "foo" # Shadow existing method `p`
puts "Am i a string? #{p}" if p = "Im a confused string"
^ get local var
if you wanted to also call the method `p`, you'd have to just through some extra hoops
or just rename the variable.
关于ruby - 在条件中声明变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29136245/