代码实现
// 定义一个泛型函数,接受两个参数和一个闭包
fn format_message<F, T>(arg1: T, arg2: T, formatter: F) -> String
where
F: Fn(T, T) -> String,
{
formatter(arg1, arg2)
}
fn main() {
// 定义一个闭包用于拼接字符串
let hello_world_formatter = |prefix: &str, suffix: &str| format!("{prefix}, {suffix}");
let hello_world = format_message("Hello", "World", hello_world_formatter);
println!("{hello_world}");
let goodbye_earth = format_message("Goodbye", "Earth", |prefix, suffix| format!("{prefix}, {suffix}"));
println!("{goodbye_earth}");
}
闭包在泛型场景下类型推断和单态化过程分析
- 类型推断:
- 在
format_message
函数调用时,编译器根据传递给函数的闭包和参数类型来推断泛型参数F
和T
的具体类型。
- 例如,在
let hello_world = format_message("Hello", "World", hello_world_formatter);
这一行中,编译器看到传递的参数"Hello"
和"World"
是字符串字面量,其类型为&str
,所以推断出T
为&str
。
- 对于闭包
hello_world_formatter
,编译器根据闭包的定义|prefix: &str, suffix: &str| format!("{prefix}, {suffix}")
,推断出闭包类型F
为Fn(&str, &str) -> String
,因为闭包接受两个&str
类型的参数并返回一个String
类型的值。
- 单态化:
- Rust编译器在编译时会对泛型代码进行单态化处理。
- 对于
format_message
函数,当编译器遇到不同的具体类型调用时,会为每种具体类型生成一份专门的代码。
- 例如,当我们调用
format_message
分别处理"Hello", "World"
和"Goodbye", "Earth"
时,编译器会生成两份format_message
函数的实例,一份T
为&str
且F
为Fn(&str, &str) -> String
的版本,另一份也是T
为&str
且F
为Fn(&str, &str) -> String
(因为闭包类型相同)的版本。这样,在运行时就可以直接执行这些专门生成的代码,提高了效率,同时保持了代码的复用性。