ruby - 在条件中声明变量

标签 ruby syntax

我知道在 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/

相关文章:

ruby - 使用 ruby​​ elasticsearch gem,如何使用多个参数进行查询

javascript - 我不太明白关于传递参数的 javascript 语法

php - 使用 pchart 和 mysql 创建图表 - 提供的示例中的正确语法

c - 如果 C11 关键字 '_Atomic' 后跟空格和左括号,是否算作类型限定符或说明符?

ruby - 如何从 ruby​​ 程序中确定控制台字符宽度?

ruby - 对象可以 `respond_to` 消息但在调用时引发错误?

ruby-on-rails - 有没有人想出如何在 Rails 3.2 中使用 Redcarpet gem for Markdown 嵌入视频?

ruby-on-rails - 如何将长数组传递到另一个页面?

syntax - 在 vim 语法中添加行尾注释

c++ - 为什么将函数名用作函数指针等同于将地址运算符应用于函数名?