什么是模式匹配
模式匹配(pattern matching )被一众函数式语言(Rust, F#, Scala,Elixir,Erlang)广泛采用。
模式匹配是一种“分发机制”,泛指各语言中用作”动态地选择行为”的特性。
具体而言,模式匹配是条件分支语句的一种形式,是更简洁、抽象化的if else/switch case 语句。
下面一段JavaScript中switch case 语句:
function print_color(color) {
switch (color) {
case "rose":
console.log("roses are red,");
break;
case "violet":
console.log("violets are blue,");
break;
default:
console.log("sugar is sweet, and so are you.");
}
}
print_color("rose"); // roses are red,
print_color("violet"); // violets are blue,
print_color("you"); // sugar is sweet, and so are you.
与之等效的rust 模式匹配实现代码为:
fn print_color(color: &str) {
match color {
"rose" => println!("roses are red,"),
"violet" => println!("violets are blue,"),
_ => println!("sugar is sweet, and so are you."),
}
}
fn main() {
print_color("rose"); // roses are red,
print_color("violet"); // violets are blue,
print_color("you"); // sugar is sweet, and so are you.
}
从以上JavaScript与Rust代码比较来看,rust模式匹配代码确实要简单一些。
但其实javascript程序员一直在使用类似模式匹配的方式做条件判断,这就是对象字面量,代码如下:
function print_color(color) {
const flowers = {
'rose':"roses are red,",
'violet':"violets are blue,",
'default':"sugar is sweet, and so are you."
}
console.log( flowers[color] ? flowers[color] : flowers['default'])
}
print_color("rose"); // roses are red,
print_color("violet"); // violets are blue,
print_color("you"); // sugar is sweet, and so are you.
这是JavaScript程序员集体自发的操作,现在ECMAScrip官方正计划把该功能标准化。
JavaScript中的模式匹配
tc39/proposal-pattern-matching: Pattern matching syntax for ECMAScript
ECMAScript在基于解构赋值的基础上,为JavaScript添加模式匹配的特性。
目前该提案已在2018年5月的TC39会议上被初步通过,目前处于Stage 1阶段。
一个
ECMAScript
标准的制作过程,包含了Stage 0
到Stage 4
5个阶段,每个阶段提交至下一阶段都需要TC39
审批通过。各个阶段介绍如下:
Stage 0
(Strawman
阶段)- 该阶段是一个开放提交阶段,任何在TC39
注册过的贡献者或TC39
成员都可以进行提交。
Stage 1
(Proposal
阶段)- 该阶段是对所提交新特性的正式建议。
Stage 2
(Draft
阶段)- 该阶段是会出现标准中的第一个版本。
Stage 3
(Canidate
阶段)- 该阶段的提议已接近完成,只需要得到提议实现方的反馈,并由用户来进一步推动。
Stage 4
(Finished
阶段)- 该阶段的会被包括到标准之中。
虽然已经到了Stage 1的阶段,但是进化的路程是比较坎坷的,各种语法层面上的纷争从来没有停过。比如:
关键字(match…with 还是case…when)
符号(->/~>)
是否支持 else clause(可以 match 所有情况的 clause)
当然最终最变成什么样子还是由 tc39 说得算。从tc39给出的示例代码来看:
代码片段1,匹配 fetch()的响应:
const res = await fetch(jsonService)
case (res) {
when {status: 200, headers: {'Content-Length': s}} ->
console.log(`size is ${s}`),
when {status: 404} ->
console.log('JSON not found'),
when {status} if (status >= 400) -> {
throw new RequestError(res)
},
}
代码片段2:
const getLength = vector => case (vector) {
when { x, y, z } -> Math.hypot(x, y, z)
when { x, y } -> Math.hypot(x, y)
when [...etc] -> vector.length
}
getLength({x: 1, y: 2, z: 3}) // 3.74165
目前JavaScript模式匹配的语法应该是:
case when
-> 瘦箭头
支持if else
自动解构赋值
JavaScript 模式匹配实现
虽然官方目前还没有出台模式匹配标准api,但是一些js类库已经实现模式匹配功能,如:
Z – Pattern Matching for Javascript
Babel Plugin
Sweet.js macro
以 Z 为例子:
安装:
npm install z
从Z中引入matches函数:
const { matches } = require('z')
实例:匹配对象属性
const { matches } = require('z')
const person = { name: 'Maria' }
matches(person)(
(x = { name: 'John' }) => console.log('John you are not welcome!'),
(x) => console.log(`Hey ${x.name}, you are welcome!`)
)
//output: `Hey Maria, you are welcome!`