C# 分片模式
1、语法
C# 允许对集合类型的分片。举个例子。
这段代码表示,我们将中间的 8 个元素提取出来,变成一个列表。它等价于这个写法:
一定要注意,1..^1
的语义是“取[1]
到 [^2]
的元素,而绝对不是取到 ^1
。因为 C# 的范围表达式是取前不取后的(前闭后开的半开区间)。
2、分片模式的弃元
分片模式也支持弃元。换句话说,我们可以在 ..
后跟上 _
来表示这一截内容我们不参与模式匹配,它和不写弃元符号的时候匹配的内容是完全一致的,只是为了确保语法的灵活性:
这里的 .. _
的 _
就是弃元用法。不过它没有意义,可以省略。
3、分片模式解构及嵌套模式匹配
分片模式允许我们对范围记号 ..
的内容进行内联变量定义,但这样的代码仍不够灵活。我还想要内联模式匹配的话,C# 是提供了这个机制的。看看这样的代码是什么意思?
[_, _, .. [_, .., 7], _]
的模式。这个模式要求我们列表集合里至少含有三个以上的元素。接着,.. [_, .., 7]
注意这里的判断模式。我们用到了三个逻辑表达式,且使用 &&
运算符连起来。下面来说一下挨个的具体判断内容。
第一个表达式
arr is { Length: >= 3 }
判断整个数组是不是不为null
的同时还至少包含 3 个元素。注意这里arr
虽然显然不空,但编译器会自动确保引用类型不空而自动产生该is not null
的模式匹配代码;第二个表达式
arr[2..^1] is { Length: >= 2 } sliced
较为复杂。它先获取arr
从第 2 索引元素(第 3 个元素)到倒数第二个元素(一定注意索引运算符是取前不取后的)。这个操作如果获取成功,则返回正常数组,否则会返回null
。因此这个is { Length: >= 2 }
验证了arr[2..^1]
是否在取分片数组的时候返回结果是否不为null
。如果不为空还要判断它的长度是不是至少包含 2 个元素。接着,如果两个判断逻辑都成功的话,那么sliced
变量就可以使用了,它就是这个分片后的数组结果;第三个表达式
sliced[^1] == 7
就是获取整个数组的最后一个元素,看看是不是 7。
所以整个表达式稍显复杂,但按顺序来看的话,就不会有任何问题了。
4、列表和分片模式的范围记号 ..
最多只能有一个
虽然有些时候我们很想写这样的代码:
我们的想法是,元素至少有一个,且整个序列里至少有一个元素的结果是 40。
可,C# 编译器并不理解这样的语法,它认为 ..
的长度不定,因此无法叠加使用,否则将无法确保使用的严谨性,比如这样的代码:
[.., 10, 20, ..]
..
这种是分片之后判断序列的模式是 [.., _]
,因此这个是可以的,因为不会冲突。
5、分片模式里的模式嵌套
如果这个数组的每一个元素并不是简单的类型,那么它里面可能包含一些别的元素。这个时候我们可能会在分片后,使用别的模式进行模式匹配:
.. [{ Prop: 42 } sliced, ..]
就是一个典型的嵌套用法。..
后跟上 [{ Prop: 42 } sliced, ..]
是一个嵌套进去的分片模式。其中,它判断分片后的序列至少包含 1 个元素,且第一个元素必须满足模式 { Prop: 42 } sliced
,也就是 Prop
属性必须是 42。如果成功匹配,那么这个元素名称可以使用 sliced