类型推断与转换 #
一、类型推断 #
1.1 自动推断 #
Rust编译器能够自动推断大多数变量的类型:
rust
fn main() {
let x = 5; // 推断为 i32
let y = 3.14; // 推断为 f64
let s = "hello"; // 推断为 &str
let v = vec![1, 2, 3]; // 推断为 Vec<i32>
println!("x: {}, y: {}, s: {}, v: {:?}", x, y, s, v);
}
1.2 上下文推断 #
编译器根据使用上下文推断类型:
rust
fn main() {
let mut v = Vec::new(); // 类型未知
v.push(10); // 根据push的参数推断为 Vec<i32>
println!("{:?}", v);
}
rust
fn main() {
// 根据返回值推断闭包参数类型
let numbers = vec![1, 2, 3, 4, 5];
let sum: i32 = numbers.iter().sum(); // 推断迭代器元素类型
println!("Sum: {}", sum);
}
1.3 泛型推断 #
rust
fn main() {
let x = "42".parse().unwrap(); // 类型未知
// 通过使用推断类型
let y: i32 = x;
println!("y: {}", y);
// 或者通过turbofish语法指定
let z = "42".parse::<i32>().unwrap();
println!("z: {}", z);
}
1.4 默认类型 #
某些情况下有默认类型:
rust
fn main() {
// 整数默认 i32
let x = 42;
// 浮点数默认 f64
let y = 3.14;
// 空Vec需要类型标注
// let v = Vec::new(); // 错误:无法推断类型
let v: Vec<i32> = Vec::new(); // 正确
println!("x: {}, y: {}, v: {:?}", x, y, v);
}
二、类型转换 #
2.1 as 关键字 #
as 用于基本类型之间的转换:
rust
fn main() {
// 整数之间转换
let a: i32 = 100;
let b: i64 = a as i64;
let c: u8 = a as u8;
// 浮点转整数(截断)
let d: f64 = 3.7;
let e: i32 = d as i32;
// 整数转浮点
let f: i32 = 5;
let g: f64 = f as f64;
// 浮点之间转换
let h: f64 = 3.14159;
let i: f32 = h as f32;
println!("i32 -> i64: {}", b);
println!("i32 -> u8: {}", c);
println!("f64 -> i32: {}", e);
println!("i32 -> f64: {}", g);
println!("f64 -> f32: {}", i);
}
2.2 溢出行为 #
rust
fn main() {
let big: i32 = 300;
let small: u8 = big as u8;
println!("300 as u8: {}", small); // 44(截断)
// 负数转无符号
let neg: i32 = -1;
let unsigned: u32 = neg as u32;
println!("-1 as u32: {}", unsigned); // 4294967295
}
2.3 字符与整数转换 #
rust
fn main() {
// 字符转整数
let c = 'A';
let code = c as u32;
println!("'A' as u32: {}", code); // 65
// 整数转字符(需要验证)
let code: u32 = 66;
if let Some(c) = char::from_u32(code) {
println!("66 as char: {}", c); // B
}
// ASCII安全转换
let byte: u8 = 67;
let c = byte as char;
println!("67 as char: {}", c); // C
}
三、From 和 Into trait #
3.1 From trait #
rust
use std::convert::From;
#[derive(Debug)]
struct Number(i32);
impl From<i32> for Number {
fn from(value: i32) -> Self {
Number(value)
}
}
fn main() {
let num = Number::from(42);
println!("{:?}", num);
// 使用 .into() 也可以(因为实现了 From)
let num: Number = 42.into();
println!("{:?}", num);
}
3.2 Into trait #
实现 From 会自动获得 Into:
rust
fn main() {
let s: String = "hello".into();
println!("{}", s);
let v: Vec<u8> = "bytes".into();
println!("{:?}", v);
}
3.3 自定义转换 #
rust
use std::convert::From;
struct Celsius(f64);
struct Fahrenheit(f64);
impl From<Celsius> for Fahrenheit {
fn from(c: Celsius) -> Self {
Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
}
}
impl From<Fahrenheit> for Celsius {
fn from(f: Fahrenheit) -> Self {
Celsius((f.0 - 32.0) * 5.0 / 9.0)
}
}
fn main() {
let c = Celsius(25.0);
let f: Fahrenheit = c.into();
println!("25°C = {}°F", f.0);
let f = Fahrenheit(77.0);
let c: Celsius = f.into();
println!("77°F = {}°C", c.0);
}
四、TryFrom 和 TryInto #
4.1 可失败转换 #
rust
use std::convert::TryFrom;
use std::convert::TryInto;
fn main() {
let big: i64 = 1_000_000_000_000;
// 尝试转换
let result: Result<i32, _> = big.try_into();
match result {
Ok(small) => println!("转换成功: {}", small),
Err(e) => println!("转换失败: {}", e),
}
// 使用 TryFrom
match i32::try_from(big) {
Ok(v) => println!("成功: {}", v),
Err(_) => println!("数值超出范围"),
}
}
4.2 自定义 TryFrom #
rust
use std::convert::TryFrom;
use std::num::TryFromIntError;
struct PositiveNumber(u32);
impl TryFrom<i32> for PositiveNumber {
type Error = TryFromIntError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value >= 0 {
Ok(PositiveNumber(value as u32))
} else {
Err(TryFromIntError::new())
}
}
}
fn main() {
let result = PositiveNumber::try_from(10);
println!("{:?}", result);
let result = PositiveNumber::try_from(-5);
println!("{:?}", result);
}
五、字符串转换 #
5.1 解析字符串 #
rust
fn main() {
// 使用 parse
let num: i32 = "42".parse().unwrap();
println!("i32: {}", num);
let pi: f64 = "3.14159".parse().unwrap();
println!("f64: {}", pi);
let b: bool = "true".parse().unwrap();
println!("bool: {}", b);
// 使用 turbofish 语法
let num = "42".parse::<i32>().unwrap();
println!("num: {}", num);
// 处理解析错误
match "abc".parse::<i32>() {
Ok(n) => println!("数字: {}", n),
Err(e) => println!("解析失败: {}", e),
}
}
5.2 转换为字符串 #
rust
fn main() {
// 使用 to_string
let s1 = 42.to_string();
let s2 = 3.14.to_string();
let s3 = true.to_string();
println!("int: {}", s1);
println!("float: {}", s2);
println!("bool: {}", s3);
// 使用 format!
let s4 = format!("Number: {}", 42);
println!("{}", s4);
}
5.3 Display 和 Debug #
rust
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl std::fmt::Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 10, y: 20 };
println!("Display: {}", p); // 使用 Display
println!("Debug: {:?}", p); // 使用 Debug
}
六、类型标注技巧 #
6.1 turbofish 语法 #
rust
fn main() {
// 泛型函数调用
let x = "42".parse::<i32>();
// 泛型方法
let v: Vec<_> = (1..10).collect::<Vec<i32>>();
// 泛型结构体
let result = Result::<i32, String>::Ok(42);
println!("{:?} {:?} {:?}", x, v, result);
}
6.2 类型下划线 #
rust
fn main() {
// 让编译器推断部分类型
let v: Vec<_> = vec![1, 2, 3];
// 收集时使用
let sum: i32 = v.iter().sum();
println!("sum: {}", sum);
}
七、实践示例 #
7.1 安全数值转换 #
rust
fn safe_divide(a: i32, b: i32) -> Option<i32> {
if b == 0 {
None
} else {
Some(a / b)
}
}
fn main() {
let results = vec![
safe_divide(10, 2),
safe_divide(10, 0),
safe_divide(15, 3),
];
for (i, result) in results.iter().enumerate() {
match result {
Some(v) => println!("结果 {}: {}", i, v),
None => println!("结果 {}: 除零错误", i),
}
}
}
7.2 单位转换 #
rust
use std::convert::From;
struct Meters(f64);
struct Feet(f64);
impl From<Feet> for Meters {
fn from(feet: Feet) -> Self {
Meters(feet.0 * 0.3048)
}
}
impl From<Meters> for Feet {
fn from(meters: Meters) -> Self {
Feet(meters.0 / 0.3048)
}
}
fn main() {
let height_in_feet = Feet(6.0);
let height_in_meters: Meters = height_in_feet.into();
println!("6 feet = {:.2} meters", height_in_meters.0);
let distance = Meters(100.0);
let distance_in_feet: Feet = distance.into();
println!("100 meters = {:.2} feet", distance_in_feet.0);
}
八、总结 #
本章学习了:
- 类型推断机制
as关键字类型转换From和IntotraitTryFrom和TryIntotrait- 字符串解析与转换
- turbofish 语法
理解类型系统是编写安全Rust代码的关键。下一章,我们将学习字符与字符串类型。
最后更新:2026-03-27