2014-09-20 35 views
-1

我的代码应该打印数组中的整数。简单的方法来理解从红宝石块返回

odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]  
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return x end } 
puts ints 

它让我在第二行显示错误 - in 'block in <main>': unexpected return (LocalJumpError)

当我删除了回报,代码工作完全按照期望。

为了找到我对块理解的错误,我阅读了相关文章post1post2。但是,我无法弄清楚被调用的方法和块的具体方式,以及为什么我的方法不正确。

有没有一些调用堆栈图的解释呢?任何简单的解释? 我很困惑,因为我以前只用Java编程过。

+0

该块是一个列表理解。你可以简单地写成:ints = odds_n_ends.select {| x | x.is_a? Integer} – 2014-09-20 21:41:31

+0

@DiegoBasch - 从未听说过这个列表理解。感谢您的建议。你能告诉我为什么我的逻辑错误吗? Ruby语言如何处理我的逻辑并抛出错误?如果我明白了,那对我来说会很容易。 – 2014-09-20 21:47:11

+0

你不在方法中,所以没有什么可以返回。参见:http://stackoverflow.com/questions/2325471/using-return-in-a-ruby-block – 2014-09-20 21:49:35

回答

1

您通常不需要担心到底要使用哪些块。

在这种情况下,return将从外部范围返回,例如,如果这些行是在一个方法,那么从那个方法。这与将一个return语句放在Java循环中一样。

其他提示:

select用于创建一个复制的阵列,其中只有满足块内的条件的元件被选择:

only_ints = odds_n_ends.select { |x| x.is_a?(Integer) } 

您使用它作为一个环为“通回到”变量是整数,在这种情况下,你会怎么做:

only_ints = [] 
odds_n_ends.each { |x| if x.is_a?(Integer) then only_ints << x end } 
+0

我试过你建议的java等价物,并没有错误。我是否正确理解这一点?'public class Stack { \t public static void main(String [] args){ \t \t int r = foo(); \t \t System.out.println(r); \t} \t public static int foo(){ \t \t int r = 0; \t \t for(int i = 0; i <5; i ++){ \t \t \t return i/2; \t \t} \t \t return r; \t} }' – 2014-09-20 21:45:23

+0

只是因为没有语法错误并不意味着你的代码是“正确的”。每次使用'0/2'即'0'时,该代码将从循环内部返回。为什么你在该方法中有无法返回的回报?我觉得你的观点不清楚。 – Kache 2014-09-20 21:48:24

+0

这就是我正在尝试的 - 在Java中的循环内部放置一个return语句。 – 2014-09-20 21:52:16

0

在红宝石的方法总是返回它的最后一条语句,所以在generall你做除非你想过早返回,否则不需要返回。

在你的情况下,你不需要返回任何东西,因为select会创建一个新的数组,只有给定块返回true的元素。随着Ruby自动返回它的使用

{ |x| x.is_a?(Integer) }

就足够了最后的陈述。 (此外,如果您考虑“返回选择的期望”,则您希望返回true而不是x,但是由于ruby并非零,所以它也可以工作......)

另一件重要的事情是理解特效(&块)和lambda表达式,这是造成你的问题的关键区别:

在一个Proc使用return将返回的proc中使用的方法

在Lambda表达式使用return将返回它就像一个值方法。

将procs视为您在方法中注入的代码块,将lambdas作为匿名方法注入。

好和易于理解阅读:Understanding Ruby Blocks, Procs and Lambdas

当传递块的方法,你应该简单地把要返回作为最后的语句中的值,也可以是在if-else子句和红宝石会使用上次实际达到的声明。

+0

谢谢。我看到了你的链接。在那林里,这意味着什么:“首先,我们将collect!方法发送给一个包含代码块的Array。”发送方法?它如何“发送”一个方法到数组?它不应该调用Array类的方法吗? – 2014-09-20 22:22:22

+1

这里一般的发送和呼叫手段基本上是一样的东西。 尽管ruby在对象/内核级别上实现了“发送”方法,它基本上执行传递给它的方法名称。所以如果你想执行收集!你可以这样做:'Array.collect!'或'Array.send(:collect!)'(冒号指出它的符号不是变量)。 在ruby'call'中引用了一种特殊的方法。它可以在一个块上使用并执行其中的代码。所以'x.respond_to(:call)'意味着对象是一个块,你可以使用'x.call'或'x.send(:call)'。 所以在ruby中发送执行方法并调用执行块。 – dfherr 2014-09-21 10:40:21

1

如果您尝试来包装你的代码的方法,那么它不会给你一个错误:

def some_method 
    odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345] 
    ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return true end } 
    puts ints 
end 

puts some_method 

这段代码的输出是真实的。但是,请等待,在哪里放入? Ruby没有达到。当你把回报放在一个Proc中时,你将返回整个方法的范围。在你的例子中,你没有任何方法来放置你的代码,所以在它遇到'return'之后,它不知道'跳转到'哪里,继续。

Array#select基本上以这种方式工作:对于数组中的每个元素(用代码中的| x |表示),它会评估刚刚放入的块,如果块的计算结果为true,那么该元素将被包含在新阵列中。尝试删除从第二行“回归”,你的代码将工作:

ints = odds_n_ends.select { |x| if x.is_a?(Integer) then true end } 

然而,这还不是最红宝石十岁上下的方式,你不必告诉红宝石明确地返回true。块({}之间的代码)就像方法一样,最后一个表达式是方法的返回值。因此,这将很好的工作:

ints = odds_n_ends.select { |x| if x.is_a?(Integer) } # imagine the code between {} is 
#a method, just without name like 'def is_a_integer?' with the value of the last expression 
#being returned. 

顺便说一句,有解决你的问题更优雅的方式:

odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]  
ints = odds_n_ends.grep(Integer) 
puts ints 

this link。它主要规定:

Returns an array of every element in enum for which Pattern === element.

要理解模式===元素,只需想象模式是一组(比方说,一个整数集)。元素可能是也可能不是该集合的一个元素(一个整数)。如何找出答案?使用===。如果您输入红宝石:

puts Integer === 34 

它会评估为真。如果你把:

puts Integer === 'hey' 

它会评价为false。

希望这有助于!