Ruby 里的 block一般翻譯成代碼塊,block 剛開始看上去有點奇怪,因為很多語言里面沒有這樣的東西。事實上它還不錯。
First-class function and Higher-order function
First-class function 和 Higher-order function 是函數式編程語言里面的概念,聽起來好像很高端的樣子,其實很很簡單的。
First-class functions 是指在某些語言里,函數是一等公民,可以把函數當做參數傳遞,
可以返回一個函數,可以把函數賦值個一個變量等等,反正就是正常值能做的事函數都能做。JavaScript 就是這樣的。舉個例子(下面的所有例子里,當我提到
JavaScript 時,示例代碼都用的 CoffeeScript):
greet = (name) -> return -> console.log "Hello, #{name}"greetToMike = greet("Mike")greetToMike() # => 輸出 "Hello, Mike"a = greetToMikea() # => 輸出 "Hello, Mike"
在上面的第四行里,greet("Mike") 返回了一個函數,所以第五行里才可以調用 greetToMike()輸出"Hello, Mike"。第六行把一個函數賦值給了a,所以第七行就可以調用這個函數了。
higher-order function 一般翻譯成高階函數,是指接受函數做參數或者返回函數的函數。
舉個非常常用的例子(用 JavaScript):
a = [ "a", "b", "c", "d" ]a.map((x) -> x + '!') #=> ["a!", "b!", "c!", "d!"]
上面例子里 map 就接受了一個匿名函數作為參數。Array.prototype里的很多方法,比如reduce, filter,every, some 等等都是高階函數,因為他們都接受函數作為參數。
高階函數非常強大,表達力很強,可以避免大量重復代碼??偟膩碚f,它就是個好東西。
Block 的本質
先來看一組 Ruby 和 CoffeeScript 代碼的對比。
a = [ "a", "b", "c", "d" ]a.map { |x| x + "!" } # => ["a!", "b!", "c!", "d!"]a.reduce { |acc, x| acc + x} # => "abcd"a = [ "a", "b", "c", "d" ]a.map((x) -> x + '!') # => ["a!", "b!", "c!", "d!"]a.reduce((acc, x) -> acc + x) # => "abcd"
這兩組代碼真的看起來超級像。我覺得這也暴露了 Ruby 的 block 的本質:高階函數的函數參數的變體。
JavaScript 里面的map 函數接受一個函數作為參數,但是 Ruby 里的 map 卻接受一個
block 作為參數。
其實 matz 早在一本書里《松本行弘的程序世界》里說了:
代碼如下: 最終來看,塊到底是什么?
...
塊也可以看作只是高階函數的一種特殊形式的語法。
...
高階函數和塊的本質一樣
...
在 Ruby 里,函數不是一等公民,沒有 first-class functions。但是在 Ruby
里怎樣使用高階函數呢?答案就是使用 block??梢灾苯佑?block,也可以用 lambda
新聞熱點
疑難解答