class Array def iterate!(&code) #注意這裡用了&符號 self.each_with_index do |n,i| self[i] = code.call(n) end endendarr = [1,2,3,4]arr.iterate! do |n| n ** 2end #[1, 4, 9, 16]
今天讀代碼的時候,被這個&符號給蒙住了。ruby語言中時不時蹦出各種奇怪的符號,而且作用不明。還不好查得。
於是認真研究了一下。
&操作符的真正含義:proc對象和塊之間的切換符號。&code 這是一個塊, code 這是一個proc對象。簡單的去掉&操作符,我們就能再次得到一個Proc對象。
===================================================
呃,其實如果沒有上下文,完全說不清楚這段。還是看下面的例子吧,運行一趟就知道了。
def math_by_anonymouse_block(a,b) yield a,benddef math_by_proc(a,b,a_proc) a_proc.call(a,b)enddef math_by_named_block(a,b,&namedblock)puts "math_by_proc a,b,namedblock"puts namedblock.class # &namedblock 是一個區塊,namedblock (去掉&)是一個proc,&操作符是個切換開關。puts math_by_proc a,b,namedblockputs "======="#lambdamylambda = lambda &namedblock puts mylambda.class puts math_by_anonymouse_block a,b,&mylambda#哈哈,下面這樣也可以puts "math_by_proc a,b,mylambda"puts math_by_proc a,b,mylambdaputs "======="#proc myproc = proc &namedblock puts myproc.class puts math_by_anonymouse_block a,b,&myproc#哈哈,下面這樣也可以puts "math_by_proc a,b,myproc"puts math_by_proc a,b,myprocputs "=======" #puts &namedblock.class#區塊不能直接賦值給一個變數。但是可以通過方法來傳遞 #myblock = &namedblock #運行不通 #puts myblock.class#所以我們用這種方式puts "math_by_anonymouse_block"puts math_by_anonymouse_block a,b,&namedblockputs "======="endmath_by_named_block(2,3) {|x,y| x*y}
運行結果:
---------- ruby run ----------math_by_proc a,b,namedblockProc6=======Proc6math_by_proc a,b,mylambda6=======Proc6math_by_proc a,b,myproc6=======math_by_anonymouse_block6=======輸出完成 (耗時 0 秒) - 正常終止
區塊就像是方法的額外匿名參數,任何方法在調用時,都可以在後面跟一個區塊。只不過如果這個方法中有yield語句,它就會調用區塊,如果沒有yield語句,就無視這個區塊。
比如:
def my_noyield puts "leave me alone. no yield !"enddef my_yield puts "I call you! come on" yieldendmy_noyield { puts "I'm coming!"}my_yield { puts "I'm coming!"}
這是我們來定義一個帶&操作符參數的方法,這就等於把之前的匿名參數變成了一個 &變數名 的參數。這個參數是一個也必然必須是一個 區塊(不是proc,去掉&才是proc)
def my_third(&myproc)puts "I call you! come on"yieldendmy_third { puts "I'm coming!"}
這裡 &myproc 是個區塊,而myproc是個proc。對於proc,我們應該可以直接調用proc.call.
所以我們來試試第4個方法:不用yield,而在方法中直接call 這個proc
def my_fourth (&myproc)puts "I call you! come on"myproc.callendmy_fourth { puts "I'm coming!"}
其實 &就是個切換開關,加上這個開關,就可以在proc和block之間切換。proc/lambda 也是一個開關(這兩個是核心方法:Kernel#proc :Creates a new procedure object from the given block. Equivalent to Proc.new
.)
def my_fivth (&myproc)puts "I call you! come on"#&&myproc.call 這個不行,不能反轉兩次?c_proc = proc &myprocc_proc.callendmy_fivth { puts "I'm coming!"}def my_sixth (&myproc)puts "I call you! come on"c_proc = lambda &myprocc_proc.callendmy_sixth { puts "I'm coming!"}
補充一個小結:
可調用對象,有以下幾種形式:塊,proc,lambda,方法。不同類的可調用對象有細微區別。
但仍然可以通過以下方法在它們之間轉換:包括Proc.new()方法,Methrod#to_proc()方法和&操作符。