2011-02-06 85 views
33

您可以分享的Ruby塊的最佳解釋是什麼?Ruby塊的最佳解釋?

使用和寫入代碼都可以佔用一塊嗎?

+1

您是否在尋找關於塊的概念的介紹,或者對其進行詳盡的參考? – Phrogz 2011-02-06 19:21:55

+16

或者你是否只是通過問你不需要答案,不打算接受,甚至不打算參加討論的問題來回答問題?我們會看看你是否回覆。 – Phrogz 2011-02-06 19:22:17

+0

這是一個有用的線程:http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ – Lucio 2015-09-21 23:18:11

回答

6

這本書「Programming Ruby」有一個很好的explanation of blocks and using them

在1.9+,傳遞到塊的參數列表變得更加複雜,從而允許定義局部變量:

do |a,b;c,d| 
    some_stuff 
end 

;c,d聲明塊內的兩個新的局部變量,不從接收值稱爲例程的yield聲明。 Ruby 1.9+保證,如果變量存在於塊之外,那麼它們將不會被塊內的同名變量踩踏。這是新的行爲; 1.8會踩踏他們。

def blah 
    yield 1,2,3,4 
end 

c = 'foo' 
d = 'bar' 

blah { |a, *b; c,d| 
    c = 'hello' 
    d = 'world' 
    puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}", "d: #{d}" 
} 

puts c, d 
# >> a: 1 
# >> b: 2,3,4 
# >> c: hello 
# >> d: world 
# >> foo 
# >> bar 

另外還有「圖示」運營商*,它在參數列表的工作原理:

do |a,*b| 
    some_stuff 
end 

將會分配第一多值的,以「一」,和所有其餘的將被捕獲在「b」中將被視爲一個數組。該*可能是在a變量:

do |*a,b| 
    some_stuff 
end 

將捕獲的變量全部通過除了最後一個,這將被傳遞給b。而且,與前兩次:

do |a,*b,c| 
    some_stuff 
end 

將指定第一個值a,最後的價值c和所有/任何中間值b

我認爲這是非常強大和光滑。

例如:

def blah 
    yield 1,2,3,4 
end 

blah { |a, *b| puts "a: #{a}", "b: #{b.join(',')}" } 
# >> a: 1 
# >> b: 2,3,4 

blah { |*a, b| puts "a: #{a.join(',')}", "b: #{b}" } 
# >> a: 1,2,3 
# >> b: 4 

blah { |a, *b, c| puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}" } 
# >> a: 1 
# >> b: 2,3 
# >> c: 4 
19

Why's (poignant) guide to ruby

由大括號包圍的任何代碼是 塊。

2.times { print "Yes, I've used chunky bacon in my examples, but never again!" }就是一個例子。

使用塊,您可以將一組 指令組合在一起,以便它們可以在您的程序中傳遞。 大括號給出了 螃蟹夾的外觀,它們已經抓取了 代碼並將它們放在一起。當 你看到這兩個鉗子,記得 ,其中的代碼已被按下 成一個單位。這就像 一個那些小的Hello Kitty盒他們 在一個與 微小的鉛筆和微觀紙, 全部塞進可以在你的手掌被隱藏 隱蔽固定 操作閃閃發光的 透明的情況下塞滿商場出售。除了塊不要 需要這麼多眯眼。 花括號也可以交易爲 單詞做和結束,這是很好的,如果 您的塊是長於一行。

loop do 
    print "Much better."  
    print "Ah. More space!" 
    print "My back was killin' me in those crab pincers." 
end 

塊參數是一個 組由管包圍 字符和由逗號分隔的變量。

|x|, |x,y|, and |up, down, all_around| are examples. 

塊參數被在塊的開始時使用 。

{ |x,y| x + y } 

在上述示例中,| X,Y |是爭論。在參數後面,我們 有一些代碼。表達式x + y將兩個參數一起添加。我想 喜歡想象管道字符 代表隧道。他們給出 滑槽的外觀,即 變量滑落。 (一個x去 下來撒鷹,而y整齊 越過她的腿。)該滑道作爲 與塊之間的通道周圍的 世界。變量 通過這個料槽(或隧道) 到塊通過。

+16

「任何由花括號包圍的代碼都是塊」除非它是一個**哈希**。 – Meltemi 2011-05-09 19:53:04

3

塊是一種在Ruby中對代碼進行分組的方法。有兩種寫塊的方法。一個使用do..end語句,另一個使用大括號括住代碼:{}。塊被認爲是Ruby編程語言中的對象,默認情況下所有函數都接受一個隱式塊參數。

下面是做同樣的事情塊的兩個例子:

 
2.times { puts 'hi' } 
2.times do 
    puts 'hi' 
end 

塊可以接收豎條內的逗號分隔的參數列表||。例如:

 
[1,2].map{ |n| n+2 } # [3, 4] 

塊(在紅寶石1.9.2)可以明確地有局部變量:

 
x = 'hello' 
2.times do |;x| 
    x = 'world' 
    puts x 
end 

=> world 
=> world 

局部變量可以用參數組合:

 
[1,2].map{ |n;x| n+2 } 

所有功能都可以接受默認塊參數:

 
def twice 
    yield 
    yield 
end 

twice { puts 'hello' } 
=> hello 
=> hello 

do..end和{}塊之間有什麼區別?按照慣例{}塊在一條線上並且做..結束塊跨越多行,因爲它們每個都更容易閱讀。主要的區別有雖與優先做的事情:

 
array = [1,2] 

puts array.map{ |n| n*10 } # puts (array.map{ |n| n*10 }) 
=> 10 
=> 20 

puts array.map do |n| n*10 end # (puts array.map) do |n| n*10 end 
=> <Enumerator:0x00000100862670> 
2

塊是與一些煩人的限制匿名一流的程序輕量級文字。他們的工作方式相同在Ruby中,因爲他們在幾乎所有其他的編程語言工作,模提到前面所限制,它們分別是:

  • 塊只能出現在參數列表
  • 最多一個塊可以出現在參數列表(它必須是最後一個參數)
27

我提供了從this answer我自己的解釋,略作修改:

「塊」在Ruby中是不一樣的,一般編程術語「代碼塊「o r「代碼塊」。

假裝下列(無效)Ruby代碼實際工作了一會兒:

def add10(n) 
    puts "#{n} + 10 = #{n+10}" 
end 

def do_something_with_digits(method) 
    1.upto(9) do |i| 
    method(i) 
    end 
end 

do_something_with_digits(add10) 
#=> "1 + 10 = 11" 
#=> "2 + 10 = 12" 
... 
#=> "9 + 10 = 19" 

雖然該代碼是無效的,其意圖傳遞一些代碼的方法和具有方法運行的代碼,是Ruby可以通過各種方式實現。其中一種方式是「塊」。

Ruby中的塊非常非常像一個方法:它可以接受一些參數併爲這些參數運行代碼。無論何時您看到foo{ |x,y,z| ... }foo do |x,y,z| ... end,這些塊都需要三個參數並在其上運行...(你甚至可能看到upto上述方法被傳遞塊。)

因爲塊是的Ruby語法的一個特殊部分,每一個方法允許傳遞一個塊。方法使用該塊取決於方法。例如:

def say_hi(name) 
    puts "Hi, #{name}!" 
end 

say_hi("Mom") do 
    puts "YOU SUCK!" 
end 
#=> Hi, Mom! 

的方法,上述傳遞塊是準備發出損傷,但由於該方法從未調用塊,當打印僅好的消息。下面是我們如何調用該塊從一個方法:

def say_hi(name) 
    puts "Hi, #{name}!" 
    if block_given? 
    yield(name) 
    end 
end 

say_hi("Mridang") do |str| 
    puts "Your name has #{str.length} letters." 
end 
#=> Hi, Mridang! 
#=> Your name has 7 letters. 

我們使用block_given?看到一塊是否沿着或者不通過。在這種情況下,我們將一個參數傳回給塊;這取決於你的方法來決定要傳遞給塊的內容。例如:

def say_hi(name) 
    puts "Hi, #{name}!" 
    yield(name, name.reverse) if block_given? 
end 

say_hi("Mridang"){ |str1, str2| puts "Is your name #{str1} or #{str2}?" } 
#=> Hi, Mridang! 
#=> Is your name Mridang or gnadirM? 

這只是(你想支持和良好的一個,和一個)對於某些類通過剛剛創建的塊實例的約定。

這不是一個詳盡的答案,因爲它不包括捕獲塊作爲參數,它們如何處理arity,在塊參數中不噴濺等,而是打算用作Blocks-Are-Lambdas的介紹。

26

Ruby塊是一種創建Proc objects的方法,它代表其他代碼可以使用的代碼。Proc對象是大括號{}(或do...end多行塊的短語,其優先級低於大括號)之間的指令,可以選擇帶參數和返回值(例如{|x,y| x+y})。特效是first-class objects,並且可以明確地被構造或隱式地獲得作爲方法的僞參數:

  1. 施工作爲Proc對象(或使用lambda關鍵字):

    add1 = Proc.new {|x| x+1} # Returns its argument plus one. 
    add1.call(1) # => 2 
    
  2. 傳遞爲方法僞參數,明確地使用&最後一個參數語法糖操作符或隱式使用block_given?/yield對:

    def twice_do(&proc) # "proc" is the block given to a call of this method. 
        2.times { proc.call() } if proc 
    end 
    twice_do { puts "OK" } # Prints "OK" twice on separate lines. 
    
    def thrice_do() # if a block is given it can be called with "yield". 
        3.times { yield } if block_given? 
    end 
    thrice_do { puts "OK" } # Prints "OK" thrice on separate lines. 
    

第二種形式通常用於Visitor patterns;數據可以作爲參數傳遞給特殊塊參數,即callyield方法。

6

任何人來對這個問題從C#的背景(或其他LANGS真的),這可能幫助:

紅寶石塊是像lambda表達式和C#匿名方法。它們是C#調用代理(和Ruby調用Proc)的東西,也就是說它們本質上是可以作爲值傳遞的函數。在Ruby和C#中,它們也可以表現爲關閉。

紅寶石:{ |x| x + 1 }

C#:x => x + 1

紅寶石:{ |name| puts "Hello there #{name}" }

C#:name => { Console.WriteLine("Hello there {0}", name); }

C#和紅寶石提供替代的方式來寫上面的例子。

紅寶石:

do |name| 
    puts "Hello there #{name}" 
end 

C#:

delegate(string name) 
{ 
    Console.WriteLine("Hello there {0}", name); 
} 

在Ruby和C#,多個語句是允許的,在Ruby中,所述第二語法以上是必需的這一點。

這些概念在許多受函數編程背後思想影響的其他語言中都可用。