JS语法如何用有C#的switch表达式

这篇文章主要为大家介绍了JS语法也可以有C#的switch表达式示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

于 C/Java 语系的语言,都有 switch 语法。switch 语法用于多分支是一个标准的用法,但这个分支语法的各分支之间存在穿透性,所以需要 break 来切断逻辑,这也成为 switch 语法中最重要的一个替在缺陷来源。此外,由于 switch 语句中各 case 的代码是在同一个作用域中,也会对代码造成一些不便。

C# 8.0 引入了switch表达式C# 的 switch 表达式有着非常丰富的语法元素,可以和模式匹配和解构等语法元素协同工作 —— 这些都不在这里细说,但是对传统的 switch语句 进行了一些改进:

  • 通过箭头 (=>) 标记处理了 case 和语句之间的一对一关系,不需要 break,不再穿透;
  • 作为表达式,可以而且必须返回值;

新的约束

  • switch 表达式一定要详尽(逻辑一定会走进某一个 case,可以通过弃元模式兜底),否则可能会在运行时引发异常。

在 C# 8.0 发布的同年,Java 12 也发布并引入了 switch 表达式预览。Java 的 switch 表达式实现比较简单,就是 switch 语句到 switch 表达式的直接转换,仅支持等值匹配。直到 2023 年 3 月 Java 20 发布,switch 表达式才开始支持模式匹配。相比之下,Kotlin 的 when 表达式走在了前面。

在这个问题上 JavaScript 似乎走在了后面,不过在语言提供 switch 表达式之前,我们可以尝试自己造个轮子。

思路当然是参考策略模式。假设有一个列表,这个列表里的每个元素都包含了两个因素:第一个用于判断是否命中,第二个是个函数,得到一个计算结果。然后写一个循环遍历列表的每个元素,一旦某个元素命中,就执行元素携带的函数获得结果,中断循环,返回结果。如果列表的最后一个元素必定命中,那么这个列表就是“详尽”的。

when 函数写法

那么这个 when 函数可能会这样写(switch 是关键字,所以使用 when 来作为函数名):

1

2

3

4

5

6

7

8

9

// JS

function when(value, ...cases) {

    for (const { is, run } of cases) {

        if (is(value)) {

            return run(value);

        }

    }

    throw new Error("非详尽");

}

这里我们假设每个情况 (case) 都含有 is 方法用于判断是否命中,用 run 方法保存命中后需要执行的操作。

分算等级”测试

相应地,我们可以经典的“拿分算等级”来进行测试:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// JS

function calcGrade(score) {

    return when(

        score,

        { is: v => v >= 0 && v < 80, run: v => `不合格 (${v})` },

        { is: v => v >= 80 && v < 100, run: v => `合格 (${v})` },

        { is: v => v == 100, run: v => `满分 (${v})` },

        { is: _ => true, run: v => `无效 (${v})` },

    );

}

for (let i = 0; i < 50; i++) {

    const v = 70 + ~~(Math.random() * 35);

    console.log(calcGrade(v));

}

在 calcGrade 实现中 when 的 case 列表最后一项采用了“永真”断言,所以走到这一项的时候一定会命中,从逻辑上来永远不会触发 Error。如果是非“详尽”的情况列表,就有可能触发 Error。

测试问题

不过现在从测试代码中就发现了两个问题:

  • is 断言是采用函数的形式,不能简单地直接按值匹配;
  • 从调用形式上来说,score 和后面的 case 元素是同级的,形式上区分不明显;
  • 每次都要写 is 和 run,条件多了写起来也烦。

继续改进 ——

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

// JS

function when(value) {

    // when 的参数先给 switch 的值

    // 返回一个函数来处理分支匹配 ②

    return function (...cases) {

        for (const [is, run] of cases) {

//                 ^^^^^^^^^ 从对象改为元组(数组)③

            if (value === is || (typeof is == "function" && is(value))) {

//                    ^^^^^^ 精确判断 ①

//                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 断言函数判断

                return  run(value);

//                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 可指定行为(函数)

            }

        }

        throw new Error("非详尽");

    };

}

function calcGrade(score) {

    return when(score)(

//         ^^^^^^^^^^^ 这里返回的是匹配处理的函数

        [v => v >= 0 && v < 80, v => `不合格 (${v})`],

        [v => v >= 80 && v < 100, v => `合格 (${v})`],

        [100, () => "满分 (100)"],

//       ^^^ 可以指定匹配的值

//            ^^ 计算不需要参数,可以不声明

        [_ => true, v => `无效 (${v})`],

//       ^^^^^^^^^ 兜底的永真断言

    );

}

为什么兜底断言必须使用一个函数呢?因为 true 值也有可能是对应一种预想的分支情况。由于这个 when 是通过语义来实现而不是通过语法来实现的,所以这里没办法定义一个安全的兜底断言语法,只有用断言函数会相对安全。

升级成 TypeScript

至此为止我们已经基本实现了 switch 表达式 (when),把它升级成 TypeScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// TypeScript

type CaseCondition<T> = T extends Function ? never : ((t: T) => boolean) | T

type Case<T, R> = [CaseCondition<T>, (t: T) => R];

function when<T>(value: T): <R>(...cases: Case<T, R>[]) => R {

    return function<R>(...cases: Case<T, R>[]): R {

        for (const [is, run] of cases) {

            if (value === is || (typeof is == "function" && is(value))) {

                return run(value);

            }

        }

        throw new Error("非详尽");

    };

}

function calcGrade(score: number) {

    return when(score)(

        [v => v >= 0 && v < 80, v => `不合格 (${v})`],

        [v => v >= 80 && v < 100, v => `合格 (${v})`],

        [100, () => "满分 (100)"],

        [_ => true, v => `无效 (${v})`],

    );

}

这段代码当然可以直接用,但是如果使用 npm 可能会更方便一点:

1

npm install @jamesfancy/when

1

2

3

4

5

6

7

8

9

10

// TypeScript

import { when } from "@jamesfancy/when";

function calcGrade(score: number) {

    return when(score)(

        [v => v >= 0 && v < 80, v => `不合格 (${v})`],

        [v => v >= 80 && v < 100, v => `合格 (${v})`],

        [100, () => "满分 (100)"],

        [_ => true, v => `无效 (${v})`],

    );

}

以上就是JS语法也可以有C# 的switch表达式的详细内容,希望可以对你有所帮助。

来源:微点阅读  https://www.weidianyuedu.com

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值