跳到主要内容

类型别名与 Never 类型

问题

Rust 的类型别名和 Never 类型(!)有什么用?

答案

类型别名(Type Alias)

类型别名用 type 关键字定义,简化复杂类型签名:

// 简化长类型
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
type Callback = Box<dyn Fn(i32) -> i32 + Send + 'static>;
type Thunk = Box<dyn FnOnce() + Send + 'static>;

// 泛型别名
type ParseResult<T> = Result<T, ParseError>;

fn parse_int(s: &str) -> ParseResult<i32> {
s.parse().map_err(|e| ParseError::new(e))
}
类型别名不创建新类型

类型别名与原类型完全等价,编译器不区分。如果需要类型安全,使用 Newtype 模式

Never 类型(!

! 表示永远不会返回值的类型(发散类型):

// 发散函数(diverging function)
fn exit(code: i32) -> ! {
std::process::exit(code);
}

fn infinite_loop() -> ! {
loop {
// 永远循环
}
}

fn always_panic() -> ! {
panic!("崩溃");
}

Never 类型的用途

1. match 分支类型统一

let value: i32 = match result {
Ok(v) => v, // i32
Err(_) => panic!(), // ! 可以强转为任何类型
};

// continue、break、return 也返回 !
let x: i32 = loop {
if condition {
break 42; // i32
}
continue; // ! → 强转为 i32
};

2. Result<T, !> 表示不可能失败

// 转换不可能失败
fn infallible() -> Result<i32, !> {
Ok(42)
}

// 可以直接 unwrap 而不会 panic
let Ok(value) = infallible(); // ! 不可能存在 Err 分支

3. Infallible 枚举

std::convert::Infallible 是稳定版的 never 类型替代品:

impl From<String> for MyType {
// 转换不可能失败
type Error = Infallible;
}

常见面试问题

Q1: 为什么 panic!() 可以出现在任何类型的表达式位置?

答案

因为 panic!() 返回 !(never 类型),而 ! 可以被强制转换(coerce)为任何类型。这是类型系统的特殊规则——一个永远不会产生值的表达式可以兼容任何类型上下文。

Q2: 类型别名在标准库中有哪些典型应用?

答案

  • type Result<T> = Result<T, std::io::Error>std::io::Result
  • type Result<T> = Result<T, std::fmt::Error>std::fmt::Result

这些别名让 IO 和格式化代码不用每次写完整的 Error 类型。

相关链接