Rust 泛型和 C++ 模板语法对比
Rust 泛型和 C++ 模板很像,都是在编译期进行单例化或实例化,为每个调用类型生成代码,减少重复的编码工作。因为 R 泛型和 C 模板有很多相同的应用场景,两种语言也为相应操作提供了语法支持。博主在记忆这些语法时感到十分困难,遂作记录和比较。
Rust 泛型(函数和结构体)的基础声明和使用语法:
// 代码引用自:https://cloud.tencent.com/developer/article/2338770
// 泛型函数
fn add<T>(a: T, b: T) -> T
whereT: std::ops::Add<Output = T>,
{a + b
}fn main() {let result = add(1, 2);println!("Result: {}", result);let result = add(3.14, 2.71);println!("Result: {}", result);
}// 泛型结构体
struct Point<T: std::fmt::Debug> {x: T,y: T,
}fn main() {let point_int = Point { x: 1, y: 2 };println!("Point: ({:?}, {:?})", point_int.x, point_int.y);let point_float = Point { x: 3.14, y: 2.71 };println!("Point: ({:?}, {:?})", point_float.x, point_float.y);
}
可以看到 Rust 在声明泛型函数或结构体时,声明泛型的尖括号放在函数名和结构体名后面。在使用泛型时,在编译器可以推断的情况下,是不需要指定泛型类型的。Rust 指定泛型类型的代码如下:
// 为泛型结构体指定泛型类型时,直接在结构体后加尖括号
struct A {u64_table: Vec<u64>,B_list: Vec<B>,
}// 为泛型函数指定泛型类型时使用了特殊的 turbofish 语法
let num = "42".parse::<u64>().unwrap();
Rust 很烦人的是,为结构体和函数指定泛型类型的语法不同。
Rust 还有个独有的,对泛型的 impl。这里看起来 impl 和 Boxed 后面各声明一次泛型是重复的,实际上前者表示这个 impl 是对泛型 T 通用的,后者表示 impl 的具体结构体是 Boxed<T>。所以如果对这个 T 有什么泛型约束的话,也是在 impl<T: ...> 这里处理。或者 impl 是针对具体类型的话,就是这样 impl Boxed<u32>
struct Boxed<T> {value: T,
}// 对所有类型 T 实现方法
impl<T> Boxed<T> {fn new(value: T) -> Self {Boxed { value }}fn get(&self) -> &T {&self.value}
}
对比 C++,其函数模板和类模板的基础语法如下:
// 函数模板示例
#include <iostream>
#include <string>// 定义一个函数模板
template <typename T>
T add(T a, T b) {return a + b;
}int main() {// 自动推导类型std::cout << add(3, 5) << "\n"; // T 推导为 intstd::cout << add(3.5, 2.1) << "\n"; // T 推导为 double// 显式指定类型std::cout << add<std::string>("Hi, ", "C++") << "\n";
}
// 类模板示例
#include <iostream>// 定义一个类模板
template <typename T>
class Box {
private:T value;
public:Box(T v) : value(v) {}void set(T v) { value = v; }T get() const { return value; }
};// 类外实现成员函数(需要重复 template)
template <typename T>
T Box<T>::get() const {return value;
}int main() {Box<int> intBox(42);std::cout << intBox.get() << "\n";Box<std::string> strBox("Hello");std::cout << strBox.get() << "\n";
}
可以看到 C++ 中调用函数模板时,可以指定泛型也可以不指定,但定义模板变量时,C++ 是不能像 Rust 那样自行推导变量类型的,必须写全泛型类型。但 C++ 中无论是函数模板还是类模板,指定类型的语法是一样的,都是最简单的<>,没有什么 turbofish。上面在类外实现成员函数和 Rust impl 有点像,而且 template 后面的 T 和 Box 后面的 T 的含义也是类似的。
C++ 中也有模板特化的语法,给出模板针对特定类型的实例化。
template <>
class Server<HTTP> : public ServerBase<HTTP> {
public:...