match 是如何用像 Rust 这样的语言实现的?
How is match implemented in a language like Rust?
我不是函数式程序员。所以我对模式匹配、模式或任何类似的东西不是很熟悉。对我来说,我只理解古老的 switch
语句的概念。
编译器如何实现匹配语句? match 和 switch 之间到底有什么区别?有一个 GNU C99 扩展允许你在切换的情况下有范围,两者之间有区别吗:
match x {
0 ... 9 => ...,
_ => ...,
}
和
switch (x) {
case 0 ... 9: ...; break;
default: ...; break;
}
请注意,第二个代码片段是一个带有此 GNU 扩展的简单 C 语言开关。
常量值的模式匹配可以实现为跳转 table 或一系列条件跳转 - 就像 switch 语句一样。允许范围不会改变这种情况。
Rust 枚举(至少是带有成员的枚举)的实现类似于标记联合,即包含标记的结构和包含成员的结构联合。
枚举上的模式匹配随后被简单地转换为其标签上的开关(将模式绑定的变量绑定到联合的成员)。所以像这样的 Rust 代码:
enum Result {
SingleResult(i32),
TwoResults(i32, i32),
Error
}
match someResult {
Result::SingleResult(res) => f(res),
Result::TwoResults(res1, res2) => g(res1, res2),
Result::Error => error()
}
将转换为(大概)与以下 C 代码相同的机器代码:
struct Result {
enum {
SingleResult, TwoResults, Error
} tag;
union {
struct {
int arg1;
} singleResult;
struct {
int arg1;
int arg2;
} twoResults;
} value;
};
switch(someResult.tag) {
case SingleResult: {
int res = someResult.value.singleResult.arg1;
f(res);
break;
}
case TwoResults: {
int res1 = someResult.value.twoResults.arg1;
int res2 = someResult.value.twoResults.arg2;
g(res1, res2);
break;
}
case Error: {
error();
break;
}
}
我不是函数式程序员。所以我对模式匹配、模式或任何类似的东西不是很熟悉。对我来说,我只理解古老的 switch
语句的概念。
编译器如何实现匹配语句? match 和 switch 之间到底有什么区别?有一个 GNU C99 扩展允许你在切换的情况下有范围,两者之间有区别吗:
match x {
0 ... 9 => ...,
_ => ...,
}
和
switch (x) {
case 0 ... 9: ...; break;
default: ...; break;
}
请注意,第二个代码片段是一个带有此 GNU 扩展的简单 C 语言开关。
常量值的模式匹配可以实现为跳转 table 或一系列条件跳转 - 就像 switch 语句一样。允许范围不会改变这种情况。
Rust 枚举(至少是带有成员的枚举)的实现类似于标记联合,即包含标记的结构和包含成员的结构联合。
枚举上的模式匹配随后被简单地转换为其标签上的开关(将模式绑定的变量绑定到联合的成员)。所以像这样的 Rust 代码:
enum Result {
SingleResult(i32),
TwoResults(i32, i32),
Error
}
match someResult {
Result::SingleResult(res) => f(res),
Result::TwoResults(res1, res2) => g(res1, res2),
Result::Error => error()
}
将转换为(大概)与以下 C 代码相同的机器代码:
struct Result {
enum {
SingleResult, TwoResults, Error
} tag;
union {
struct {
int arg1;
} singleResult;
struct {
int arg1;
int arg2;
} twoResults;
} value;
};
switch(someResult.tag) {
case SingleResult: {
int res = someResult.value.singleResult.arg1;
f(res);
break;
}
case TwoResults: {
int res1 = someResult.value.twoResults.arg1;
int res2 = someResult.value.twoResults.arg2;
g(res1, res2);
break;
}
case Error: {
error();
break;
}
}