返回介绍

8.1 泛型

发布于 2024-10-13 11:25:30 字数 2617 浏览 0 评论 0 收藏 0

泛型(generics)是一种类模板技术,允许使用一些在实例化时才指定的类型(参数化类型)。可用于函数、结构体、枚举和方法,极大减少重复代码。

#[derive(Debug)]
struct Data<T> {
  x: T
}

fn main() {
  // let a: Data<i32> = Data{ x: 10 };
  // let b: Data<f32> = Data{ x: 1.1 };

  let a = Data{ x: 10 };
  let b = Data{ x: 1.1 };

  assert_eq!(a.x, 10);
  assert_eq!(b.x, 1.1);
}
fn main() {
  // let x = Vec::new();
  //     ^^^^^^^^ cannot infer type for type parameter `T`

  let x: Vec<i32> = Vec::new();
  let y = Vec::<i32>::new();
}

允许有多个类型参数,如 Rsult<T, E>

单态

编译器对泛型进行 单态化 (monomorphization)处理。也就是结合泛型模板和类型参数,生成具体的类型定义。如此,便不会有运行期行为,也不会有任何性能损失。

编译后只有 Data<i32>Data<f64> 两个不同类型,并无 Data<T>

(gdb) ptype a
type = struct demo::Data<i32> {
  x: i32,
}

(gdb) ptype b
type = struct demo::Data<f64> {
  x: f64,
}

即便是函数,也会生成独立代码。

fn test<T>(x: T) -> T {
  x
}

fn main() {
  test(1);
  test("abc");
}
(gdb) disass/s

test(1);
=> mov  edi,0x1
   call   0x5555555671c0 <demo::test<i32>>

test("abc");
   lea  rdi,[rip+0xffffffffffffaa4e]
   mov  esi,0x3
   call   0x5555555671d0 <demo::test<&str>>

约束

使用特征(trait)约束类型参数,要求其具备特定功能。多个约束以加号相连。

use std::fmt::{Debug, Display};

fn test<T: Debug + Display>(x: T) {
  println!("{}", x);         // Display
  println!("{:?}", x);       // Debug
}

fn main() {
  test(1);
  test("abc");
}

改用 where 表达约束,使代码更清晰易读。

use std::fmt::{Debug, Display};

fn test<A, B>(x: A, y: B) where
  A: Debug,             // 多个依旧用 + 号。
  B: Display
{
  println!("x: {:?}, y: {}", x, y);
}

fn main() {
  test("abc", 123);
}

也可对泛型结构等进行约束。

use std::fmt::{Debug};

#[derive(Debug)]
struct Data<T> where 
  T: Debug
{
  x: T
}

fn main() {
  let d = Data{x: 1};
  println!("{:?}", d);

  // struct N;
  // let d = Data{x: N};
  //     ^^^^ the trait `Debug` is not implemented for `N`
}

其他

无参数泛型函数,须显式指定类型。

为避免编译器将尖括号解析成比较运算符,通常写成 func::<T>

use std::default::Default;

fn default_value<T: Default>() -> T {
  T::default()
}

fn main() {
  assert_eq!(default_value::<i32>(), 0);
}

const 将常量值模版化。

use std::fmt::Debug;

fn print_array<T: Debug, const N: usize>(v: [T; N]) {
  println!("{:?}", v);
}

fn main() {
  print_array([1, 2, 3]);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文