这篇文章会用不一样的观点来介绍Ruby and Rails
,写过 Javascript
的读者们,相信这篇文章对你们会比较有感觉。
Ruby
为正统的OOP
语言,但Ruby也 开了一扇functional programming
的窗,让我们可以使用,而今天我就要为读者们打开这扇窗户。
首先要介绍什麽是区块block
?block
为以 do ... end
或者以 {}
包裹住的区块,以下面的例子来说,{|_| _ + 1}
就是 block
[1, 2, 3].map {|_| _ + 1}
在 Ruby 什麽东西都是物件,不过也有例外,例如Block
本身就不是物件。Block
没有办法单独的存在,也没办法指定给某个变数。虽然是例外,但 block
却是Ruby
常用的技巧。不仅面试常考,很多底层也很常使用block
{|_| _ + 1} #=> 不行这样表示
a = {|_| _ + 1} #=> 当作变数也不行
#==== 取而代之,我们可以这样写
a = -> (v) { v + 1 }
下面的写法为 Proc
。
a = -> (v) { v + 1 }
Block
没有办法单独存在,但我们可以使用 Proc
类别,把 Block 物件化。Proc
全名称为 Proceduce
,而Proc
一共有两种,一种为lambda
, 而另外一种为 Proc
#======= lambda
-> { 'foo' }
#=> #<Proc:0x00007f883d48dfd8@(irb):2 (lambda)>
lambda { 'foo' }
#=> #<Proc:0x00007f883d49f0f8@(irb):3 (lambda)>
#======= Proc
Proc.new { 'foo' }
#=> #<Proc:0x00007f883d4afc50@(irb):4>
lambda { 'foo' } #=> Proc
-> { 'foo' }.class #=> Proc
Proc.new { 'foo' } #=> Proc
接着,讲讲如何执行procedure
adder = -> (x) {x+1}
# 4种 notation
adder.call(1)
adder.(1)
adder.=== 1
adder[1]
一般来说,除了call
这种 notation 以外,其他用法长相太奇异,一般来说都不建议使用,但如果想要用proc
,又想要在code review
通关的话,建议使用最後一种notation
,因为可以被当作使用阵列蒙混过去。
def arb_mtd
# 程序码逻辑(多行)
adder = -> (x) {x+1}
# 程序码逻辑(多行)
adder[1]
# 程序码逻辑(多行)
end
Ruby on Rails
是很物件导向的语言,而汉汉老师曾经有一段时间因前端部门的人太少,我被转调到前端部门。听到大家讨论在前端专案实作什麽写法的时候,第一次听到functional programming
这个名词。起初对於什麽是functional programming
一头雾水,看到同事的程序码吓到,原来functional programming
在专案上竟然能够呈现得那麽好看!
主要也是同事也好看。
总之开始看下列例子。以下的例子为将[1, 2, 3]
的阵列分别加1,回传新的值
[1, 2, 3].map {|_| _ + 1}
我们使用Javascript
来诠释以上的写法
/* es6 map */
[1, 2, 3].map(e => e + 1)
/* map in lodash */
map([1, 2, 3], e => e + 1)
依样画葫芦,我们也将原本Ruby
的写法进行改写。这里先不要理会&
的写法,我们只是尽量将JS
, Ruby
写法达到一致。
[1, 2, 3].map(&->(x) { x + 1 })
Ruby
, JS
两个语言使用了匿名函式如下
e => e + 1 # anonymous in js
->(x) { x + 1 } # anonymous in ruby
并且,这两个匿名函式皆为 Pure function,又为 First Class Citizens。今天突然讲了很多新名词,不过我会一一介绍给大家。
我们先介绍Pure function
,Pure Function
有一个最重要的特性是当输入了相同的值,吐出的值都是相等的结果,也有人说这种特性是可快取的(cached)。Vue2
的 computed property
即为一种Pure function
,使用Pure function
不会有side effect,意即不会改变任何结果!
什麽是First Class Citizens?First Class Citizens 为将function
视为参数,指派到其他function
使用。以上例来说,->(x) { x + 1 }
为第一等公民,它将自己提供给别人给使用。
使用其他function
作为参数使用的function
,或者回传结果为function
都为 Higher Order Function
。上述的map
使用了匿名函数,因此map
高阶函数 higher order function。
我们举个简单的例子讲解 Higher Order Function
和 First Class Citizens
之间的关系
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert( "OK" );
}
function showCancel() {
alert( "Canceled" );
}
// usage: functions showOk, showCancel are passed as arguments to ask
ask("Do you agree?", showOk, showCancel);
上述例子我们可以知道 showOk
, showCancel
都被ask
拿来取用,因此上述例子的 Higher Order Function
为 ask
,而 showOk
, showCancel
则为 First Class Citizens
。
以下列出 Javascript
常见的高阶函数,其中hello
, square
是First Class Citizens
,而使用hello
, square
的setTimeout
, map
则为 higher order function
。
// setTimeout
const hello = () => console.log("Hello!")
window.setTimeout((hello), 1000)
// map (用lodash的观点来看)
const square = (n) => (n * n);
_.map([4, 8], square);
// => [16, 64]
在 Rails
不难发现Higher Order Function
的踪迹,以下举一些复杂的例子。
# gem: AASM
#=== 定义订单完成动作
event(:complete, success: -> { update_status_time!(:done_at) }) do
transitions from: [Status::WAITING, Status::PROCESSING], to: Status::DONE
end
首先我们看AASM
的例子,它把success: -> { update_status_time!(:done_at) }
传进去event
,因此event
在这边为 higher order function
,而-> { update_status_time!(:done_at) }
为 First Class Citizens
# gem: descent_exposure
#===== 取代 controller instance variable 的好用工具
module Admin
class ReturnOrdersController < ApplicationController
expose :return_orders, -> { ReturnOrder.all }
expose :return_order, build: -> (return_order_params, scope) { scope.build(return_order_params) },
scope: -> { ReturnOrder.all }
expose :order, -> { return_order.order }
end
end
上面的例子,毫无疑问的,expose
为 higher order function
,而build: -> {...}, scope: -> {...}
则为被调用的First Class Citizens
自从踏入了Functional Programming
的领域之後,Block
变成是我很喜欢的章节之一。今天介绍了 Ruby 和 Functional Programming 之间关联,我们也会继续在Day8-9 介绍Block
。
<<: [Day 03] 用 Gradle 安装 Exposed 框架
一. 前言 词性标注 Part Of Speech(後面皆简称POS),简单来说就是将文章、句子中,...
Android 手机 行动电话 小人图示 talkback 无障碍按钮 导览列 捷径 协助工具按钮开...
新零售行销模式案例,全通路时代来临该如何布局,一直以来都在担任辅导顾问为中小企业解决网路行销问题但都...
前言 对於大量的资料处理,使用串列的走访是一种十分没有效率的方法,其效率会根据串列的长度而不断线性成...
上次提到了在wordpress建置时选择主题的方式,本次就来看一下有关Themes购买,一个是在wo...