类型推断与转换 #

一、类型推断 #

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 关键字类型转换
  • FromInto trait
  • TryFromTryInto trait
  • 字符串解析与转换
  • turbofish 语法

理解类型系统是编写安全Rust代码的关键。下一章,我们将学习字符与字符串类型。

最后更新:2026-03-27