我一直认为rubyists因为样式偏好而选择在ruby中隐含返回(更少的单词=更简洁)。但是,有人可以向我确认在下面的示例中,您实际上必须隐式返回,否则预期的功能将无效吗? (预期的功能是能够将一个句子分成单词,并为每个单词返回“用元音开始”或“用辅音开始”)
# With Implicit Returns
def begins_with_vowel_or_consonant(words)
words_array = words.split(" ").map do |word|
if "aeiou".include?(word[0,1])
"Begins with a vowel" # => This is an implicit return
else
"Begins with a consonant" # => This is another implicit return
end
end
end
# With Explicit Returns
def begins_with_vowel_or_consonant(words)
words_array = words.split(" ").map do |word|
if "aeiou".include?(word[0,1])
return "Begins with a vowel" # => This is an explicit return
else
return "Begins with a consonant" # => This is another explicit return
end
end
end
现在,我知道肯定有很多方法可以使这些代码更高效,更好,但我这样做的原因是为了说明隐含返回的必要性。有人可以向我证实,确实需要隐含的回报,而不仅仅是一种风格选择吗?
编辑: 这是一个例子来说明我想要展示的内容:
# Implicit Return
begins_with_vowel_or_consonant("hello world") # => ["Begins with a consonant", "Begins with a consonant"]
# Explicit Return
begins_with_vowel_or_consonant("hello world") # => "Begins with a consonant"
答案 0 :(得分:5)
方法的隐式返回值是方法中计算的最后一个表达式。
在您的情况下,您注释的两行中的 都不是最后一个表达式。得到评估的最后一个表达式是对words_array
的赋值(BTW完全没用,因为它是最后一个表达式,之后无法使用该变量)。
现在,赋值表达式的值是多少?在此特定情况下,它是指定的值map
方法的返回值,即Array
。所以,这就是方法返回的内容。
在 second 示例中,在map
的第一次迭代中,您将点击两个return
中的一个,从而立即从该方法返回。但是,在第一个示例中,您将始终遍历整个words
数组。
问题是不隐式和显式返回是不同的,问题是你声称隐含返回的两行不是。
答案 1 :(得分:1)
这种情况发生的原因是因为return语句在块内。如果return语句只是一个函数内部,那么执行流程就像你期望的那样。 ruby中的块和返回(以及关于此问题的break语句)是一个奇怪的野兽。让我们用一个简单的例子来捕捉你的要求:
def no_return()
(1..10).each do |i|
puts i
end
puts 'end'
end
def yes_return()
(1..10).each do |i|
puts i
return
end
puts 'end'
end
如果你同时运行这两个,你会看到第一个将打印数字1-10和单词'end',如你所料,但第二个函数只打印出1.这是因为ruby内部将returns(和break语句)实现为异常。抛出这些异常时,会使用一个名为“catch table”的查找表来尝试查找执行流程应该继续的位置。如果没有找到,ruby内部将搜索rb_control_frame结构的堆栈,寻找指向我们正在执行的代码的指针。因此,在您的情况下,抛出异常并且最接近的指针(就堆栈帧而言)位于方法的末尾,从而导致整个方法的终止。这就是为什么你甚至不会看到'结束'的印刷。
no_return说明:
0000 trace 1 ( 3)
0002 putnil
0003 getdynamic i, 0
0006 send :puts, 1, nil, 8, <ic:0>
0012 leave
yes_return说明:
0000 trace 1 ( 3)
0002 putnil
0003 getdynamic i, 0
0006 send :puts, 1, nil, 8, <ic:0>
0012 pop
0013 trace 1 ( 4)
0015 putnil
0016 throw 1
0018 leave
重要的一点是在yes_return指令中,有'throw 1'实际上是一个实现为抛出(和捕获)异常的return语句。以相同的方式打破工作,除了他们'扔2'。
要查看所有框架和捕获表的实际说明,请查看我不久前放在一起的应用程序: http://rubybytes.herokuapp.com/
有关更多信息,请查看Pat Shaughnessy的博客,特别是此条目以获取更多信息: http://patshaughnessy.net/2012/6/29/how-ruby-executes-your-code
另一个无耻的插件,如果你是java,请查看我的java版本的rubybytes at javabytes.herokuapp.com查看反汇编的java字节码(对不起它是无链接的,你必须将url复制并粘贴到你的浏览器中)。
答案 2 :(得分:0)
return
将从产生于块的方法返回,因此您需要隐式或使用next