489 lines
10 KiB
Plaintext
489 lines
10 KiB
Plaintext
/* ===== 模块4:match 语句 =====
|
||
* test18_match — match 枚举匹配 + 整数匹配(类似 switch)
|
||
* 难度:3/5
|
||
* 验证点:枚举匹配、带数据绑定、结构体字段绑定、枚举指针、
|
||
* 整数自变量匹配、默认分支 _
|
||
*/
|
||
|
||
/* ---- 简单枚举(无数据) ---- */
|
||
type Color = enum {
|
||
Red;
|
||
Green;
|
||
Blue;
|
||
}
|
||
|
||
/* ---- 带 i32 数据的枚举 ---- */
|
||
type Optional = enum {
|
||
Some: i32;
|
||
None;
|
||
}
|
||
|
||
/* ---- 带结构体数据的枚举 ---- */
|
||
type Point = struct {
|
||
var x: i32;
|
||
var y: i32;
|
||
}
|
||
|
||
type Shape = enum {
|
||
Circle: i32;
|
||
Rect: Point;
|
||
}
|
||
|
||
/* ---- 多变体枚举 ---- */
|
||
type ActionResult = enum {
|
||
Success: i32;
|
||
NotFound;
|
||
Timeout: i32;
|
||
Error: *u8;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 1: 无数据枚举匹配
|
||
* ============================================================ */
|
||
|
||
fn test_color_match() i32 {
|
||
var c: Color = Color { .Red };
|
||
var val: i32 = 0;
|
||
|
||
match c {
|
||
.Red => { val = 1; },
|
||
.Green => { val = 2; },
|
||
.Blue => { val = 3; }
|
||
}
|
||
if val != 1 { ret 1; }
|
||
|
||
c = Color { .Green };
|
||
match c {
|
||
.Red => { val = 0; },
|
||
.Green => { val = 2; },
|
||
.Blue => { val = 0; }
|
||
}
|
||
if val != 2 { ret 2; }
|
||
|
||
c = Color { .Blue };
|
||
match c {
|
||
.Red => { val = 0; },
|
||
.Green => { val = 0; },
|
||
.Blue => { val = 3; }
|
||
}
|
||
if val != 3 { ret 3; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 2: 带 i32 数据枚举匹配
|
||
* ============================================================ */
|
||
|
||
fn test_optional_match() i32 {
|
||
var o: Optional = Optional { .Some = 42 };
|
||
|
||
match o {
|
||
.Some(val) => {
|
||
if val != 42 { ret 1; }
|
||
},
|
||
.None => {
|
||
ret 2;
|
||
}
|
||
}
|
||
|
||
o = Optional { .None };
|
||
var is_none: i32 = 0;
|
||
match o {
|
||
.Some(val) => {},
|
||
.None => { is_none = 1; }
|
||
}
|
||
if is_none != 1 { ret 3; }
|
||
|
||
/* 多次提取不同值 */
|
||
o = Optional { .Some = 99 };
|
||
match o {
|
||
.Some(val) => {
|
||
if val != 99 { ret 4; }
|
||
},
|
||
.None => { ret 5; }
|
||
}
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 3: 带结构体数据枚举匹配(多字段绑定)
|
||
* ============================================================ */
|
||
|
||
fn test_shape_match() i32 {
|
||
/* Circle: 单数据 */
|
||
var s: Shape = Shape { .Circle = 10 };
|
||
match s {
|
||
.Circle(r) => {
|
||
if r != 10 { ret 1; }
|
||
},
|
||
.Rect(w, h) => {
|
||
ret 2;
|
||
}
|
||
}
|
||
|
||
/* Rect: 结构体数据,绑定为 (x, y) 对应 Point 的字段 */
|
||
s = Shape { .Rect = Point { .x = 3, .y = 4 } };
|
||
match s {
|
||
.Circle(r) => { ret 3; },
|
||
.Rect(w, h) => {
|
||
if w != 3 { ret 4; }
|
||
if h != 4 { ret 5; }
|
||
}
|
||
}
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 4: 多数据变体枚举匹配
|
||
* ============================================================ */
|
||
|
||
fn test_action_result_match() i32 {
|
||
var r: ActionResult = ActionResult { .Success = 200 };
|
||
match r {
|
||
.Success(code) => {
|
||
if code != 200 { ret 1; }
|
||
},
|
||
.NotFound => {
|
||
ret 2;
|
||
},
|
||
.Timeout(ms) => {
|
||
ret 3;
|
||
},
|
||
.Error(msg) => {
|
||
ret 4;
|
||
}
|
||
}
|
||
|
||
r = ActionResult { .NotFound };
|
||
var found: i32 = 1;
|
||
match r {
|
||
.Success(code) => { found = 0; },
|
||
.NotFound => { },
|
||
.Timeout(ms) => { found = 0; },
|
||
.Error(msg) => { found = 0; }
|
||
}
|
||
if found != 1 { ret 5; }
|
||
|
||
r = ActionResult { .Timeout = 5000 };
|
||
match r {
|
||
.Success(code) => { ret 6; },
|
||
.NotFound => { ret 7; },
|
||
.Timeout(ms) => {
|
||
if ms != 5000 { ret 8; }
|
||
},
|
||
.Error(msg) => { ret 9; }
|
||
}
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 5: 枚举指针匹配
|
||
* ============================================================ */
|
||
|
||
fn test_ptr_match() i32 {
|
||
var c: Color = Color { .Green };
|
||
var p: *Color = &c;
|
||
|
||
match p {
|
||
.Red => { ret 1; },
|
||
.Green => { },
|
||
.Blue => { ret 2; }
|
||
}
|
||
|
||
/* 修改后通过指针匹配 */
|
||
c = Color { .Blue };
|
||
match p {
|
||
.Red => { ret 3; },
|
||
.Green => { ret 4; },
|
||
.Blue => { }
|
||
}
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 6: match 作为函数返回值
|
||
* ============================================================ */
|
||
|
||
fn classify_color(c: Color) i32 {
|
||
match c {
|
||
.Red => { ret 1; },
|
||
.Green => { ret 2; },
|
||
.Blue => { ret 3; }
|
||
}
|
||
ret 0;
|
||
}
|
||
|
||
fn test_match_in_func() i32 {
|
||
var r: i32;
|
||
|
||
r = classify_color(Color { .Red });
|
||
if r != 1 { ret 1; }
|
||
|
||
r = classify_color(Color { .Green });
|
||
if r != 2 { ret 2; }
|
||
|
||
r = classify_color(Color { .Blue });
|
||
if r != 3 { ret 3; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 7: match 嵌套在循环中
|
||
* ============================================================ */
|
||
|
||
fn test_match_in_loop() i32 {
|
||
var i: i32 = 0;
|
||
var sum: i32 = 0;
|
||
|
||
while i < 3 {
|
||
var o: Optional;
|
||
if i == 0 {
|
||
o = Optional { .Some = 10 };
|
||
} else if i == 1 {
|
||
o = Optional { .Some = 20 };
|
||
} else {
|
||
o = Optional { .Some = 30 };
|
||
}
|
||
|
||
match o {
|
||
.Some(val) => {
|
||
sum = sum + val;
|
||
},
|
||
.None => { }
|
||
}
|
||
i = i + 1;
|
||
}
|
||
if sum != 60 { ret 1; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 8: 整数 match(类似 switch)
|
||
* ============================================================ */
|
||
|
||
fn test_int_match() i32 {
|
||
var x: i32 = 2;
|
||
var result: i32 = 0;
|
||
|
||
match x {
|
||
1 => { result = 10; },
|
||
2 => { result = 20; },
|
||
3 => { result = 30; }
|
||
}
|
||
if result != 20 { ret 1; }
|
||
|
||
/* 匹配第一个值 */
|
||
x = 1;
|
||
match x {
|
||
1 => { result = 100; },
|
||
2 => { result = 200; },
|
||
3 => { result = 300; }
|
||
}
|
||
if result != 100 { ret 2; }
|
||
|
||
/* 匹配最后一个值 */
|
||
x = 3;
|
||
match x {
|
||
1 => { result = 1000; },
|
||
2 => { result = 2000; },
|
||
3 => { result = 3000; }
|
||
}
|
||
if result != 3000 { ret 3; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 9: 整数 match 带默认分支 _
|
||
* ============================================================ */
|
||
|
||
fn test_int_match_default() i32 {
|
||
var x: i32 = 99;
|
||
var result: i32 = 0;
|
||
|
||
match x {
|
||
1 => { result = 1; },
|
||
2 => { result = 2; },
|
||
_ => { result = 99; }
|
||
}
|
||
if result != 99 { ret 1; }
|
||
|
||
/* 默认分支未触发 */
|
||
x = 1;
|
||
match x {
|
||
1 => { result = 1; },
|
||
2 => { result = 2; },
|
||
_ => { result = 99; }
|
||
}
|
||
if result != 1 { ret 2; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 10: 整数 match 多个值跳转到相同逻辑
|
||
* ============================================================ */
|
||
|
||
fn test_int_match_multi() i32 {
|
||
var x: i32 = 2;
|
||
var result: i32 = 0;
|
||
|
||
/* 每个分支独立 */
|
||
match x {
|
||
0 => { result = 0; },
|
||
1 => { result = 1; },
|
||
2 => { result = 2; },
|
||
3 => { result = 3; }
|
||
}
|
||
if result != 2 { ret 1; }
|
||
|
||
/* 负数和零 */
|
||
x = -1;
|
||
match x {
|
||
-1 => { result = -1; },
|
||
0 => { result = 0; },
|
||
1 => { result = 1; }
|
||
}
|
||
if result != -1 { ret 2; }
|
||
|
||
x = 0;
|
||
match x {
|
||
-1 => { result = -1; },
|
||
0 => { result = 0; },
|
||
1 => { result = 1; }
|
||
}
|
||
if result != 0 { ret 3; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 11a: match 多值 fallthrough: 1, 2, 3 => body
|
||
* ============================================================ */
|
||
|
||
fn test_int_match_fallthrough() i32 {
|
||
var x: i32;
|
||
var r: i32;
|
||
|
||
/* 三个值映射到同一个 body */
|
||
x = 1; r = 0;
|
||
match x {
|
||
1, 2, 3 => { r = 10; },
|
||
4, 5 => { r = 20; }
|
||
}
|
||
if r != 10 { ret 1; }
|
||
|
||
x = 3;
|
||
match x {
|
||
1, 2, 3 => { r = 10; },
|
||
4, 5 => { r = 20; }
|
||
}
|
||
if r != 10 { ret 2; }
|
||
|
||
x = 5;
|
||
match x {
|
||
1, 2, 3 => { r = 10; },
|
||
4, 5 => { r = 20; }
|
||
}
|
||
if r != 20 { ret 3; }
|
||
|
||
/* 单一值(非fallthrough)仍然正常 */
|
||
x = 7; r = 0;
|
||
match x {
|
||
1 => { r = 1; },
|
||
7 => { r = 7; }
|
||
}
|
||
if r != 7 { ret 4; }
|
||
|
||
/* 多个负数值 */
|
||
x = -2; r = 0;
|
||
match x {
|
||
-3, -2, -1 => { r = 100; },
|
||
0, 1 => { r = 200; }
|
||
}
|
||
if r != 100 { ret 5; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 测试 11b: match with body 中修改变量
|
||
* ============================================================ */
|
||
|
||
fn test_match_with_side_effects() i32 {
|
||
var x: i32 = 3;
|
||
var acc: i32 = 0;
|
||
|
||
match x {
|
||
1 => { acc = acc + 1; },
|
||
2 => { acc = acc + 2; },
|
||
3 => { acc = acc + 3; },
|
||
4 => { acc = acc + 4; }
|
||
}
|
||
if acc != 3 { ret 1; }
|
||
|
||
/* 再次 match 同一个变量 */
|
||
match x {
|
||
1 => { acc = acc + 1; },
|
||
2 => { acc = acc + 2; },
|
||
3 => { acc = acc + 3; },
|
||
4 => { acc = acc + 4; }
|
||
}
|
||
if acc != 6 { ret 2; }
|
||
|
||
ret 0;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 主函数
|
||
* ============================================================ */
|
||
|
||
fn main() i32 {
|
||
var r: i32;
|
||
|
||
r = test_color_match();
|
||
if r != 0 { ret r; }
|
||
|
||
r = test_optional_match();
|
||
if r != 0 { ret r + 10; }
|
||
|
||
r = test_shape_match();
|
||
if r != 0 { ret r + 20; }
|
||
|
||
r = test_action_result_match();
|
||
if r != 0 { ret r + 30; }
|
||
|
||
r = test_ptr_match();
|
||
if r != 0 { ret r + 40; }
|
||
|
||
r = test_match_in_func();
|
||
if r != 0 { ret r + 50; }
|
||
|
||
r = test_match_in_loop();
|
||
if r != 0 { ret r + 60; }
|
||
|
||
r = test_int_match();
|
||
if r != 0 { ret r + 70; }
|
||
|
||
r = test_int_match_default();
|
||
if r != 0 { ret r + 80; }
|
||
|
||
r = test_int_match_multi();
|
||
if r != 0 { ret r + 90; }
|
||
|
||
r = test_match_with_side_effects();
|
||
if r != 0 { ret r + 100; }
|
||
|
||
r = test_int_match_fallthrough();
|
||
if r != 0 { ret r + 110; }
|
||
|
||
ret 0;
|
||
}
|