2010-05-14 10 views
5

Używam ruby ​​1.8.7.blok ruby ​​i zwracanie czegoś z bloku

p = lambda { return 10;} 
def lab(block) 
    puts 'before' 
    puts block.call 
    puts 'after' 
end 
lab p 

Nad wyjściem kodu jest

before 
10 
after 

I refactored sam kod do tego

def lab(&block) 
    puts 'before' 
    puts block.call 
    puts 'after' 
end 
lab { return 10; } 

Teraz jestem coraz LocalJumpError: nieoczekiwany powrotnej.

Dla mnie oba kody robią to samo. Tak, w pierwszym przypadku przekazuję proc, aw drugim przypadku przechodzę blok. Ale blok & zamienia ten blok na proc. Więc proc.call powinien zachowywać się tak samo.

I tak widziałem ten post Using 'return' in a Ruby block

Odpowiedz

8

Po przejściu do bloku z &, konwertujesz go do proc. Ważną kwestią jest to, że proc i lambda są różne (lambda jest faktycznie podklasą proc), w szczególności w jaki sposób radzą sobie z powrotem.

Więc refactored kod jest rzeczywiście odpowiednikiem:

p = Proc.new { return 10;} 
def lab(block) 
    puts 'before' 
    puts block.call 
    puts 'after' 
end 
lab p 

który generuje również LocalJumpError.

Oto dlaczego: Zwrot proc powraca z zakresu leksykalnego, ale lambda powraca do zakresu wykonywania. Więc podczas gdy lambda wraca do lab, przekazany do niej kod powraca do zewnętrznego zakresu, w którym został zadeklarowany. Lokalny błąd skoku oznacza, że ​​nie ma dokąd pójść, ponieważ nie ma funkcji zamykającej.

The Ruby Programming Language mówi to najlepiej:

Procs have block-like behavior and lambdas have method-like behavior

Po prostu trzeba śledzić, co używasz gdzie. Jak sugerowali inni, wszystko co musisz zrobić, to usunąć return ze swojego bloku, a wszystko będzie działać zgodnie z przeznaczeniem.

5

return wewnątrz bloku powróci ze sposobu blok jest w nie z bloku. Aby powrócić z bloku, użyj next (tak się nazywa, ponieważ dzięki iteratorom-metodom takim jak each i map powrót z bloku oznacza w zasadzie przejście do następnej iteracji pętli).

Należy zauważyć, że gdy zwracana wartość jest ostatnim ocenianym wyrażeniem w bloku, w ogóle nie potrzebujesz żadnego zwrotu, tj. lab { 10 } zrobi to samo.

0

Blok zawiera kontekst, w którym jest podany, więc return próbuje wrócić z linii lab { return 10; }. Możesz faktycznie wykonać tę pracę (czasami nawet w użyteczny sposób), umieszczając tę ​​linię wewnątrz metody, która następnie zwróci (tzn. "Po" nie zostanie wydrukowane).

Aby zwrócić wartość 10 do block.call, należy pominąć return (lub zastępować).

0

Chyba wystarczy nieprawidłowego bloku, zanim przejdzie go:

foo = lambda { return 10 } 

def trace_block(&fn) 
    puts 'before calling fn' 
    puts fn.call 
    puts 'after caling fn' 
end 

trace_block(&foo) 

wyjściowa:

before calling fn 
    10 
    after caling fn 

Więcej informacji:

+0

http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ to naprawdę fajny napis. Dziękuję udostępnianie. –