第18章 高级特征

文章目录

第18章 高级特征

Rust语言的设计哲学强调安全性和性能,但同时也提供了在必要时突破安全限制的能力。本章将深入探讨Rust的高级特征,包括不安全Rust操作、高级trait使用技巧、高级类型系统特性以及函数和闭包的高级用法。这些特性让Rust能够在保持内存安全的同时,实现系统级编程所需的底层控制能力。

18.1 不安全的Rust

Rust通过所有权系统、借用检查和类型系统在编译时保证了内存安全。然而,在某些情况下,我们需要绕过这些安全检查来执行一些底层操作。这就是不安全Rust的用武之地。不安全Rust并不是关闭所有的安全检查,而是在特定区域内允许执行一些通常被禁止的操作,同时要求程序员对这些操作的安全性负责。

不安全超能力

在不安全Rust中,我们可以执行五种被称作"不安全超能力"的操作:

  1. 解引用裸指针
  2. 调用不安全函数或方法
  3. 访问或修改可变静态变量
  4. 实现不安全trait
  5. 访问union的字段

这些操作被标记为不安全是因为编译器无法验证它们的安全性,需要程序员手动确保操作的正确性。

rust 复制代码
// 不安全块的基本语法
unsafe {
    // 在这里执行不安全操作
}

// 不安全函数
unsafe fn dangerous_operation() {
    // 函数体
}

// 调用不安全函数必须在unsafe块中
unsafe {
    dangerous_operation();
}

解引用裸指针

裸指针是Rust中的一种原始指针类型,分为不可变裸指针*const T和可变裸指针*mut T。与引用不同,裸指针不受Rust所有权规则的限制,但也不享有编译器的安全性保证。

rust 复制代码
fn demonstrate_raw_pointers() {
    let mut num = 5;

    // 创建裸指针是安全的
    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;

    // 但解引用裸指针必须在unsafe块中
    unsafe {
        println!("r1 points to: {}", *r1);
        println!("r2 points to: {}", *r2);
        
        // 通过可变裸指针修改值
        *r2 = 10;
        println!("After modification, num = {}", num);
    }

    // 创建指向任意地址的裸指针
    let address = 0x012345usize;
    let r = address as *const i32;
    
    // 解引用任意地址是极度危险的!
    // unsafe { println!("Value at address {:p}: {}", r, *r); }
    // 这可能导致段错误或读取垃圾数据
}

// 裸指针与引用的区别
fn pointer_vs_reference() {
    let x = 10;
    let y = 20;
    
    // 引用必须始终有效且符合借用规则
    let ref1 = &x;
    // let ref2 = &mut x; // 错误:不能同时存在可变和不可变引用
    
    // 裸指针没有这些限制
    let ptr1 = &x as *const i32;
    let ptr2 = &mut x as *mut i32; // 注意:这里x不是mut,但转换是允许的
    let ptr3 = &y as *const i32;
    
    unsafe {
        println!("ptr1: {}", *ptr1);
        // *ptr2 = 30; // 这是未定义行为!x不是mut
        println!("ptr3: {}", *ptr3);
    }
}

裸指针的主要使用场景包括:

  • 与C代码交互
  • 构建安全抽象
  • 性能关键代码
  • 实现特殊的数据结构

调用不安全函数或方法

不安全函数或方法的定义以unsafe关键字开头,表示该函数具有编译器无法验证的安全前提条件。调用这些函数必须在unsafe块中,表明调用者已经验证了这些前提条件。

rust 复制代码
// 不安全函数定义
unsafe fn dangerous_operation(ptr: *mut i32) {
    if !ptr.is_null() {
        *ptr = 42;
    }
}

// 包装不安全函数的安全接口
fn safe_operation(ptr: *mut i32) -> Result<(), &'static str> {
    if ptr.is_null() {
        Err("Null pointer provided")
    } else {
        unsafe {
            dangerous_operation(ptr);
        }
        Ok(())
    }
}

// 使用外部C函数
extern "C" {
    fn abs(input: i32) -> i32;
    fn malloc(size: usize) -> *mut std::ffi::c_void;
    fn free(ptr: *mut std::ffi::c_void);
}

fn use_foreign_functions() {
    unsafe {
        // 调用C标准库的abs函数
        let result = abs(-10);
        println!("Absolute value: {}", result);
        
        // 分配内存
        let ptr = malloc(100);
        if !ptr.is_null() {
            println!("Allocated 100 bytes at {:p}", ptr);
            // 使用分配的内存...
            free(ptr);
        }
    }
}

// 不安全方法
struct UnsafeContainer {
    data: *mut i32,
    length: usize,
}

impl UnsafeContainer {
    // 不安全方法
    unsafe fn get_unchecked(&self, index: usize) -> i32 {
        *self.data.add(index)
    }
    
    unsafe fn set_unchecked(&mut self, index: usize, value: i32) {
        *self.data.add(index) = value;
    }
    
    // 安全包装方法
    fn get(&self, index: usize) -> Option<i32> {
        if index < self.length {
            unsafe { Some(self.get_unchecked(index)) }
        } else {
            None
        }
    }
    
    fn set(&mut self, index: usize, value: i32) -> Result<(), &'static str> {
        if index < self.length {
            unsafe { self.set_unchecked(index, value); }
            Ok(())
        } else {
            Err("Index out of bounds")
        }
    }
}

创建不安全代码的安全抽象

将不安全代码封装在安全接口后面是Rust的重要设计模式。这样可以在享受不安全操作带来的能力的同时,对外提供安全的API。

rust 复制代码
use std::slice;

// 安全地分割可变切片
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = slice.len();
    let ptr = slice.as_mut_ptr();

    // 运行时检查
    assert!(mid <= len, "mid index out of bounds");

    unsafe {
        (
            // 从原始指针创建切片
            slice::from_raw_parts_mut(ptr, mid),
            slice::from_raw_parts_mut(ptr.add(mid), len - mid),
        )
    }
}

// 自定义向量类型的安全抽象
struct MyVec<T> {
    ptr: *mut T,
    cap: usize,
    len: usize,
}

impl<T> MyVec<T> {
    fn new() -> Self {
        Self {
            ptr: std::ptr::null_mut(),
            cap: 0,
            len: 0,
        }
    }
    
    fn push(&mut self, value: T) {
        if self.len == self.cap {
            self.grow();
        }
        
        unsafe {
            // 将值写入当前长度位置
            self.ptr.add(self.len).write(value);
        }
        self.len += 1;
    }
    
    fn pop(&mut self) -> Option<T> {
        if self.len == 0 {
            None
        } else {
            self.len -= 1;
            unsafe {
                // 读取最后一个元素
                Some(self.ptr.add(self.len).read())
            }
        }
    }
    
    fn get(&self, index: usize) -> Option<&T> {
        if index < self.len {
            unsafe {
                // 返回引用
                Some(&*self.ptr.add(index))
            }
        } else {
            None
        }
    }
    
    fn grow(&mut self) {
        // 增长逻辑(简化版)
        let new_cap = if self.cap == 0 { 1 } else { self.cap * 2 };
        let new_ptr = unsafe {
            let layout = std::alloc::Layout::array::<T>(new_cap).unwrap();
            std::alloc::alloc(layout) as *mut T
        };
        
        if !self.ptr.is_null() {
            // 复制旧数据到新位置
            unsafe {
                std::ptr::copy_nonoverlapping(self.ptr, new_ptr, self.len);
                // 释放旧内存
                let layout = std::alloc::Layout::array::<T>(self.cap).unwrap();
                std::alloc::dealloc(self.ptr as *mut u8, layout);
            }
        }
        
        self.ptr = new_ptr;
        self.cap = new_cap;
    }
}

// 为MyVec实现Drop trait来防止内存泄漏
impl<T> Drop for MyVec<T> {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            // 逐个调用元素的析构函数
            for i in 0..self.len {
                unsafe {
                    std::ptr::drop_in_place(self.ptr.add(i));
                }
            }
            // 释放内存
            unsafe {
                let layout = std::alloc::Layout::array::<T>(self.cap).unwrap();
                std::alloc::dealloc(self.ptr as *mut u8, layout);
            }
        }
    }
}

使用extern函数调用外部代码

Rust可以通过外部函数接口(FFI)与其他语言进行交互,特别是C语言。这是通过extern块来实现的。

rust 复制代码
// 声明外部C函数
extern "C" {
    // C标准库函数
    fn printf(format: *const std::ffi::c_char, ...) -> i32;
    fn strlen(s: *const std::ffi::c_char) -> usize;
    
    // 自定义C函数
    fn my_c_function(x: i32) -> i32;
}

// 提供Rust函数给C调用
#[no_mangle]  // 防止名称修饰
pub extern "C" fn rust_function(x: i32) -> i32 {
    x * 2
}

// 安全的C字符串包装
struct CString {
    ptr: *mut std::ffi::c_char,
}

impl CString {
    fn new(s: &str) -> Option<Self> {
        // 将Rust字符串转换为C字符串
        let c_string = std::ffi::CString::new(s).ok()?;
        let ptr = c_string.into_raw();
        Some(Self { ptr })
    }
    
    fn as_ptr(&self) -> *const std::ffi::c_char {
        self.ptr
    }
    
    unsafe fn print(&self) {
        // 调用C的printf函数
        printf(self.as_ptr());
    }
}

impl Drop for CString {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            unsafe {
                // 重新获取CString来正确释放内存
                let _ = std::ffi::CString::from_raw(self.ptr);
            }
        }
    }
}

fn demonstrate_ffi() {
    // 创建C字符串
    if let Some(c_str) = CString::new("Hello from Rust!\n") {
        unsafe {
            c_str.print();
            
            // 使用C的strlen函数
            let len = strlen(c_str.as_ptr());
            println!("String length according to C: {}", len);
        }
    }
    
    // 调用自定义C函数
    unsafe {
        let result = my_c_function(10);
        println!("Result from C function: {}", result);
    }
}

访问或修改可变静态变量

在Rust中,全局变量被称为静态变量。不可变静态变量是安全的,但可变静态变量在多线程环境中可能引发数据竞争,因此访问它们需要unsafe块。

rust 复制代码
// 不可变静态变量 - 安全的
static HELLO_WORLD: &str = "Hello, world!";
static MAX_CONNECTIONS: u32 = 100;

// 可变静态变量 - 访问需要unsafe
static mut COUNTER: u32 = 0;
static mut GLOBAL_DATA: Vec<String> = Vec::new();

// 线程安全的计数器增加
fn increment_counter(inc: u32) {
    unsafe {
        COUNTER += inc;
    }
}

// 安全的全局数据访问接口
fn add_global_data(item: String) -> Result<(), &'static str> {
    unsafe {
        // 检查数据有效性等前提条件
        if item.is_empty() {
            return Err("Cannot add empty string");
        }
        GLOBAL_DATA.push(item);
        Ok(())
    }
}

fn get_global_data() -> Vec<String> {
    unsafe {
        GLOBAL_DATA.clone()  // 返回副本以避免并发问题
    }
}

// 使用原子操作实现线程安全的全局计数器
use std::sync::atomic::{AtomicU32, Ordering};

static ATOMIC_COUNTER: AtomicU32 = AtomicU32::new(0);

fn increment_atomic_counter() {
    ATOMIC_COUNTER.fetch_add(1, Ordering::SeqCst);
}

fn get_atomic_counter() -> u32 {
    ATOMIC_COUNTER.load(Ordering::SeqCst)
}

fn demonstrate_statics() {
    // 访问不可变静态变量是安全的
    println!("{}", HELLO_WORLD);
    println!("Max connections: {}", MAX_CONNECTIONS);
    
    // 访问可变静态变量需要unsafe
    unsafe {
        println!("Initial counter: {}", COUNTER);
    }
    
    increment_counter(5);
    
    unsafe {
        println!("Counter after increment: {}", COUNTER);
    }
    
    // 使用安全的接口
    add_global_data("Hello".to_string()).unwrap();
    add_global_data("World".to_string()).unwrap();
    
    let data = get_global_data();
    println!("Global data: {:?}", data);
    
    // 使用原子计数器
    increment_atomic_counter();
    increment_atomic_counter();
    println!("Atomic counter: {}", get_atomic_counter());
}

实现不安全trait

当trait具有编译器无法验证的不变量时,它必须被标记为unsafe。实现这样的trait也需要使用unsafe impl

rust 复制代码
// 不安全trait的例子
unsafe trait UnsafeTrait {
    // 这个方法有不安全的前提条件
    fn dangerous_operation(&self);
    
    // 这个方法返回的引用必须满足特定的生命周期要求
    fn get_data(&self) -> &str;
}

// 标记为Send和Sync需要unsafe impl的情况
struct MyUnsafeType {
    data: *mut i32,
    len: usize,
}

// 我们需要手动保证MyUnsafeType是线程安全的
unsafe impl Send for MyUnsafeType {}
unsafe impl Sync for MyUnsafeType {}

impl MyUnsafeType {
    fn new() -> Self {
        Self {
            data: std::ptr::null_mut(),
            len: 0,
        }
    }
    
    // 不安全的方法
    unsafe fn initialize(&mut self, size: usize) {
        let layout = std::alloc::Layout::array::<i32>(size).unwrap();
        self.data = std::alloc::alloc(layout) as *mut i32;
        self.len = size;
    }
}

// 实现不安全trait
unsafe impl UnsafeTrait for MyUnsafeType {
    fn dangerous_operation(&self) {
        unsafe {
            if !self.data.is_null() && self.len > 0 {
                println!("Performing dangerous operation on data at {:p}", self.data);
            }
        }
    }
    
    fn get_data(&self) -> &str {
        // 返回静态字符串,满足生命周期要求
        "Unsafe data"
    }
}

// 使用场景:与硬件交互
struct HardwareRegister {
    address: usize,
}

unsafe trait HardwareAccess {
    fn read(&self) -> u32;
    fn write(&mut self, value: u32);
}

unsafe impl HardwareAccess for HardwareRegister {
    fn read(&self) -> u32 {
        unsafe {
            // 从内存映射的硬件寄存器读取
            (self.address as *const u32).read_volatile()
        }
    }
    
    fn write(&mut self, value: u32) {
        unsafe {
            // 写入内存映射的硬件寄存器
            (self.address as *mut u32).write_volatile(value)
        }
    }
}

fn demonstrate_unsafe_traits() {
    let mut register = HardwareRegister { address: 0x1000 };
    
    unsafe {
        // 因为实现了HardwareAccess trait,我们可以调用这些方法
        register.write(0x1234);
        let value = register.read();
        println!("Read value: 0x{:x}", value);
    }
    
    let mut unsafe_type = MyUnsafeType::new();
    unsafe {
        unsafe_type.initialize(10);
    }
    unsafe_type.dangerous_operation();
}

18.2 高级trait

trait是Rust中定义共享行为的核心机制。在前面的章节中我们已经了解了trait的基础知识,现在让我们深入探讨trait的高级用法。

关联类型

关联类型在trait定义中充当类型占位符,允许我们在实现trait时指定具体的类型。这提供了比泛型参数更清晰的接口。

rust 复制代码
// 使用关联类型的trait
pub trait Iterator {
    type Item;  // 关联类型
    
    fn next(&mut self) -> Option<Self::Item>;
}

// 自定义集合类型
struct Stack<T> {
    items: Vec<T>,
}

impl<T> Stack<T> {
    fn new() -> Self {
        Self { items: Vec::new() }
    }
    
    fn push(&mut self, item: T) {
        self.items.push(item);
    }
    
    fn pop(&mut self) -> Option<T> {
        self.items.pop()
    }
}

// 为Stack实现Iterator
impl<T> Iterator for Stack<T> {
    type Item = T;  // 指定关联类型的具体类型
    
    fn next(&mut self) -> Option<Self::Item> {
        self.pop()
    }
}

// 更复杂的关联类型示例
trait Graph {
    type Node;
    type Edge;
    
    fn nodes(&self) -> Vec<Self::Node>;
    fn edges(&self, node: &Self::Node) -> Vec<Self::Edge>;
    fn connect(&mut self, from: Self::Node, to: Self::Node, edge: Self::Edge);
}

// 具体图实现
struct SimpleGraph {
    nodes: Vec<usize>,
    edges: Vec<(usize, usize, String)>,
}

impl Graph for SimpleGraph {
    type Node = usize;
    type Edge = String;
    
    fn nodes(&self) -> Vec<Self::Node> {
        self.nodes.clone()
    }
    
    fn edges(&self, node: &Self::Node) -> Vec<Self::Edge> {
        self.edges
            .iter()
            .filter(|(from, to, _)| from == node || to == node)
            .map(|(_, _, label)| label.clone())
            .collect()
    }
    
    fn connect(&mut self, from: Self::Node, to: Self::Node, edge: Self::Edge) {
        self.edges.push((from, to, edge));
    }
}

// 关联类型与泛型参数的对比
trait GenericConverter<T> {
    fn convert(&self, value: T) -> T;
}

trait AssociatedConverter {
    type Input;
    type Output;
    
    fn convert(&self, value: Self::Input) -> Self::Output;
}

// 使用关联类型的优势:更清晰的函数签名
fn process_converter<C>(converter: &C, value: C::Input) -> C::Output 
where 
    C: AssociatedConverter,
{
    converter.convert(value)
}

fn demonstrate_associated_types() {
    let mut stack = Stack::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);
    
    // 使用迭代器
    while let Some(item) = stack.next() {
        println!("Popped: {}", item);
    }
    
    let mut graph = SimpleGraph {
        nodes: vec![1, 2, 3],
        edges: Vec::new(),
    };
    
    graph.connect(1, 2, "edge_1_2".to_string());
    graph.connect(2, 3, "edge_2_3".to_string());
    
    println!("Nodes: {:?}", graph.nodes());
    println!("Edges from node 2: {:?}", graph.edges(&2));
}

默认泛型参数和运算符重载

在trait定义中,我们可以为泛型参数指定默认类型。这在运算符重载等场景中特别有用。

rust 复制代码
use std::ops::Add;

// 使用默认泛型参数的Add trait
// trait Add<Rhs = Self> {
//     type Output;
//     fn add(self, rhs: Rhs) -> Self::Output;
// }

// 为自定义类型实现Add
#[derive(Debug, PartialEq, Clone, Copy)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Point;
    
    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

// 使用不同的Rhs类型
struct Meters(f64);
struct Millimeters(f64);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;
    
    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000.0))
    }
}

// 更复杂的运算符重载
use std::ops::{Mul, Index, IndexMut};

impl Mul<i32> for Point {
    type Output = Point;
    
    fn mul(self, scalar: i32) -> Point {
        Point {
            x: self.x * scalar,
            y: self.y * scalar,
        }
    }
}

// 为矩阵实现索引
struct Matrix {
    data: [[f64; 3]; 3],
}

impl Index<usize> for Matrix {
    type Output = [f64; 3];
    
    fn index(&self, index: usize) -> &Self::Output {
        &self.data[index]
    }
}

impl IndexMut<usize> for Matrix {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.data[index]
    }
}

fn demonstrate_operator_overloading() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 3, y: 4 };
    let p3 = p1 + p2;
    println!("p1 + p2 = {:?}", p3);
    
    let scaled = p3 * 2;
    println!("p3 * 2 = {:?}", scaled);
    
    let distance_mm = Millimeters(1500.0) + Meters(2.0);
    println!("1500mm + 2m = {}mm", distance_mm.0);
    
    let mut matrix = Matrix {
        data: [
            [1.0, 2.0, 3.0],
            [4.0, 5.0, 6.0],
            [7.0, 8.0, 9.0],
        ],
    };
    
    println!("Matrix[1][2] = {}", matrix[1][2]);
    matrix[0][0] = 10.0;
    println!("After modification: Matrix[0][0] = {}", matrix[0][0]);
}

完全限定语法:消除歧义

当存在多个具有相同名称的trait方法或关联函数时,我们需要使用完全限定语法来明确指定要调用的是哪个实现。

rust 复制代码
trait Pilot {
    fn fly(&self);
    fn name() -> String;
}

trait Wizard {
    fn fly(&self);
    fn name() -> String;
}

struct Human;

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*");
    }
    
    fn name() -> String {
        "Human".to_string()
    }
}

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.");
    }
    
    fn name() -> String {
        "Pilot".to_string()
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("Up!");
    }
    
    fn name() -> String {
        "Wizard".to_string()
    }
}

fn demonstrate_fully_qualified_syntax() {
    let person = Human;
    
    // 默认调用Human的固有方法
    person.fly();
    
    // 使用完全限定语法调用trait方法
    Pilot::fly(&person);
    Wizard::fly(&person);
    
    // 对于关联函数,必须使用完全限定语法
    println!("A baby dog is called a {}", Human::name());
    println!("A baby dog is called a {}", <Human as Pilot>::name());
    println!("A baby dog is called a {}", <Human as Wizard>::name());
    
    // 更复杂的例子
    trait Animal {
        type Species;
        fn species_name() -> String;
    }
    
    struct Dog;
    
    impl Animal for Dog {
        type Species = String;
        
        fn species_name() -> String {
            "Canis lupus familiaris".to_string()
        }
    }
    
    // 使用完全限定语法访问关联类型和函数
    let _species: <Dog as Animal>::Species = "Labrador".to_string();
    println!("Dog species: {}", <Dog as Animal>::species_name());
}

父trait:在另一个trait中使用某个trait的功能

父trait(supertrait)要求实现某个trait的类型也必须实现另一个trait,这允许我们在trait定义中使用其他trait的功能。

rust 复制代码
use std::fmt;

// 父trait:要求实现OutlinePrint的类型也必须实现Display
trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        let output = self.to_string();  // 使用Display的to_string方法
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

// 为满足条件的类型实现OutlinePrint
struct Point {
    x: i32,
    y: i32,
}

// 必须先实现Display
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

// 现在可以实现OutlinePrint
impl OutlinePrint for Point {}

// 更复杂的父trait示例
trait Vehicle {
    fn get_speed(&self) -> f64;
}

trait Car: Vehicle {
    fn get_wheel_count(&self) -> u32;
    
    // 可以使用父trait的方法
    fn describe(&self) -> String {
        format!(
            "A car with {} wheels traveling at {:.1} mph",
            self.get_wheel_count(),
            self.get_speed()
        )
    }
}

struct Sedan {
    speed: f64,
}

impl Vehicle for Sedan {
    fn get_speed(&self) -> f64 {
        self.speed
    }
}

impl Car for Sedan {
    fn get_wheel_count(&self) -> u32 {
        4
    }
}

fn demonstrate_supertraits() {
    let point = Point { x: 3, y: 4 };
    point.outline_print();
    
    let sedan = Sedan { speed: 65.5 };
    println!("{}", sedan.describe());
    
    // 接受实现Car trait的参数,它自动满足Vehicle
    fn print_vehicle_info<T: Car>(vehicle: &T) {
        println!("Speed: {:.1}", vehicle.get_speed());
        println!("Wheels: {}", vehicle.get_wheel_count());
    }
    
    print_vehicle_info(&sedan);
}

newtype模式

newtype模式通过创建新类型来绕过孤儿规则(orphan rule),从而在外部类型上实现外部trait。

rust 复制代码
use std::fmt;

// 孤儿规则:我们不能为Vec<T>实现Display,因为两者都在外部定义
// impl<T> fmt::Display for Vec<T> { ... } // 错误!

// 使用newtype模式绕过限制
struct Wrapper(Vec<String>);

impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.join(", "))
    }
}

// 更实用的newtype示例:类型安全的值域
struct Percentage(f64);

impl Percentage {
    fn new(value: f64) -> Option<Self> {
        if (0.0..=100.0).contains(&value) {
            Some(Self(value))
        } else {
            None
        }
    }
    
    fn value(&self) -> f64 {
        self.0
    }
}

impl fmt::Display for Percentage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:.1}%", self.0)
    }
}

// 为newtype实现Deref来获得内部类型的访问
use std::ops::Deref;

impl Deref for Wrapper {
    type Target = Vec<String>;
    
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

// 使用newtype实现自定义行为
struct Meters(f64);

impl Meters {
    fn to_centimeters(&self) -> Centimeters {
        Centimeters(self.0 * 100.0)
    }
}

struct Centimeters(f64);

impl Centimeters {
    fn to_meters(&self) -> Meters {
        Meters(self.0 / 100.0)
    }
}

fn demonstrate_newtype_pattern() {
    // 基本newtype使用
    let w = Wrapper(vec![
        "hello".to_string(),
        "world".to_string(),
    ]);
    println!("w = {}", w);
    
    // 使用Deref自动解引用
    println!("First element: {}", w[0]);
    println!("Length: {}", w.len());
    
    // 类型安全的百分比
    if let Some(pct) = Percentage::new(75.5) {
        println!("Percentage: {}", pct);
    }
    
    if let Some(pct) = Percentage::new(150.0) {
        println!("This won't print: {}", pct);
    } else {
        println!("Invalid percentage value");
    }
    
    // 单位安全转换
    let distance_m = Meters(2.5);
    let distance_cm = distance_m.to_centimeters();
    println!("{} meters = {} centimeters", distance_m.0, distance_cm.0);
    
    let back_to_m = distance_cm.to_meters();
    println!("{} centimeters = {} meters", distance_cm.0, back_to_m.0);
}

18.3 高级类型

Rust的类型系统非常丰富,除了基本类型外,还提供了许多高级类型特性来帮助编写更安全、更表达力的代码。

类型别名

类型别名使用type关键字创建,主要用于简化复杂类型的书写和提高代码可读性。

rust 复制代码
// 基本类型别名
type Kilometers = i32;
type UserId = u64;
type Result<T> = std::result::Result<T, std::io::Error>;

// 简化复杂类型
type Thunk = Box<dyn Fn() + Send + 'static>;
type ComplexResult<T> = Result<T, Box<dyn std::error::Error>>;
type StringMap<V> = std::collections::HashMap<String, V>;

// 在函数签名中使用类型别名
fn process_thunk(f: Thunk) {
    f();
}

fn get_user_name(id: UserId) -> Option<String> {
    Some(format!("User_{}", id))
}

fn read_config() -> ComplexResult<String> {
    Ok("config content".to_string())
}

// 泛型类型别名
type Pair<T> = (T, T);
type Matrix<T> = Vec<Vec<T>>;

fn demonstrate_type_aliases() {
    // 使用类型别名
    let distance: Kilometers = 5;
    let user_id: UserId = 12345;
    
    println!("Distance: {} km", distance);
    println!("User ID: {}", user_id);
    
    // 使用复杂类型别名
    let thunk: Thunk = Box::new(|| println!("Hello from thunk!"));
    process_thunk(thunk);
    
    let mut map: StringMap<i32> = StringMap::new();
    map.insert("key".to_string(), 42);
    println!("Map value: {}", map["key"]);
    
    // 使用泛型别名
    let point: Pair<f64> = (3.14, 2.71);
    let matrix: Matrix<i32> = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    println!("Point: ({}, {})", point.0, point.1);
    println!("Matrix: {:?}", matrix);
    
    // 处理结果别名
    match read_config() {
        Ok(config) => println!("Config: {}", config),
        Err(e) => println!("Error reading config: {}", e),
    }
}

永不返回的never type

Rust有一个特殊的!类型,称为never type,表示计算永远不会完成。它在发散函数(不返回的函数)和模式匹配中非常有用。

rust 复制代码
// 发散函数返回never type
fn forever() -> ! {
    loop {
        println!("I run forever!");
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

fn panic_with_message(msg: &str) -> ! {
    panic!("{}", msg);
}

// 在模式匹配中使用never type
fn process_result(result: Result<i32, &str>) -> i32 {
    match result {
        Ok(value) => value,
        Err(msg) => panic_with_message(msg),
    }
}

// never type可以强制转换为任何类型
fn match_with_never() {
    let guess = "42";
    
    let number: i32 = match guess.trim().parse() {
        Ok(num) => num,
        Err(_) => {
            // 这个分支的类型是!,可以强制转换为i32
            return;  // 这里实际返回的是(),但编译器知道这个分支不会产生值
        }
    };
    
    println!("Parsed number: {}", number);
}

// 实际应用:无限服务器循环
fn run_server() -> ! {
    loop {
        // 模拟处理请求
        println!("Processing request...");
        std::thread::sleep(std::time::Duration::from_secs(2));
    }
}

// 在泛型代码中使用never type
fn unwrap_or_continue<T>(option: Option<T>) -> T {
    match option {
        Some(value) => value,
        None => {
            // continue的类型是!,可以强制转换为T
            continue;
        }
    }
}

fn demonstrate_never_type() {
    // 处理Result的例子
    let good_result: Result<i32, &str> = Ok(42);
    let bad_result: Result<i32, &str> = Err("Something went wrong");
    
    println!("Good result: {}", process_result(good_result));
    // println!("Bad result: {}", process_result(bad_result)); // 这会panic
    
    // 模拟服务器运行(注释掉以避免实际运行无限循环)
    // run_server();
    
    // 在循环中使用
    let mut count = 0;
    loop {
        count += 1;
        if count > 3 {
            break;
        }
        
        let value = unwrap_or_continue(Some(count));
        println!("Processing value: {}", value);
    }
    
    // never type在错误处理中的高级用法
    fn try_operation() -> Result<i32, Box<dyn std::error::Error>> {
        // 模拟可能失败的操作
        if std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs() % 2 == 0
        {
            Ok(42)
        } else {
            Err("Operation failed".into())
        }
    }
    
    match try_operation() {
        Ok(value) => println!("Success: {}", value),
        Err(_) => {
            eprintln!("Operation failed, exiting...");
            std::process::exit(1);  // exit的返回类型是!
        }
    };
}

动态大小类型和Sized trait

动态大小类型(DST)是在编译时大小未知的类型,Rust通过Sized trait来跟踪类型的大小信息。

rust 复制代码
// 最常见的DST:str
fn process_str(s: &str) {
    println!("String slice: '{}' (length: {})", s, s.len());
}

// 另一个DST:[T]
fn process_slice(slice: &[i32]) {
    println!("Slice: {:?} (length: {})", slice, slice.len());
}

// 泛型函数默认要求Sized
fn generic_function<T>(t: T) {
    // T默认需要是Sized的
    println!("Size of T: {}", std::mem::size_of::<T>());
}

// 使用?Sized放宽限制
fn flexible_function<T: ?Sized>(t: &T) {
    // 现在T可以是DST,但我们只能通过引用使用它
    println!("Working with sized or unsized type");
}

// 自定义DST-like行为
trait TraitForDST {
    fn do_something(&self);
}

// 为所有类型实现trait,包括DST
impl<T: ?Sized> TraitForDST for T {
    fn do_something(&self) {
        println!("Doing something with a type");
    }
}

// 使用Box来在堆上存储DST
fn create_dst_on_heap() -> Box<dyn std::fmt::Display> {
    Box::new(42)
}

fn demonstrate_sized_trait() {
    // 基本类型都是Sized的
    let x = 42;
    let y = "hello";
    let z = vec![1, 2, 3];
    
    generic_function(x);
    generic_function(y);
    generic_function(z);
    
    // 使用?Sized的函数可以接受DST
    flexible_function(&x);
    flexible_function(y);  // y是&str,str是DST
    flexible_function("world");
    
    // 为所有类型调用trait方法
    x.do_something();
    y.do_something();
    
    // 在堆上存储DST
    let boxed_dst = create_dst_on_heap();
    println!("Boxed DST: {}", boxed_dst);
    
    // 使用切片(DST)
    let array = [1, 2, 3, 4, 5];
    let slice = &array[1..4];  // 切片是DST
    process_slice(slice);
    
    // 字符串切片(DST)
    let string = String::from("Hello, World!");
    let string_slice = &string[7..12];
    process_str(string_slice);
    
    // trait对象也是DST
    let display_vec: &dyn std::fmt::Display = &vec![1, 2, 3];
    println!("Display vec: {}", display_vec);
    
    let debug_vec: &dyn std::fmt::Debug = &vec![4, 5, 6];
    println!("Debug vec: {:?}", debug_vec);
}

// 高级用法:自定义智能指针处理DST
struct MySmartPointer<T: ?Sized> {
    data: Box<T>,
}

impl<T: ?Sized> MySmartPointer<T> {
    fn new(data: Box<T>) -> Self {
        Self { data }
    }
}

impl<T: ?Sized> std::ops::Deref for MySmartPointer<T> {
    type Target = T;
    
    fn deref(&self) -> &T {
        &self.data
    }
}

fn demonstrate_custom_dst_handling() {
    // 存储字符串切片
    let pointer1 = MySmartPointer::new(Box::new("Hello") as Box<str>);
    println!("String: {}", *pointer1);
    
    // 存储trait对象
    let pointer2 = MySmartPointer::new(Box::new(42) as Box<dyn std::fmt::Display>);
    println!("Display: {}", *pointer2);
    
    // 存储切片
    let data = vec![1, 2, 3, 4, 5];
    let slice_ptr = MySmartPointer::new(Box::new(data[1..4].to_vec().into_boxed_slice()));
    println!("Slice: {:?}", &**slice_ptr);
}

18.4 高级函数和闭包

函数和闭包是Rust中的一等公民,它们具有强大的表达能力。让我们深入探讨它们的高级用法。

函数指针

函数指针允许我们将函数作为值传递,它们在需要动态选择函数或与C代码交互时非常有用。

rust 复制代码
// 普通函数
fn add_one(x: i32) -> i32 {
    x + 1
}

fn multiply_by_two(x: i32) -> i32 {
    x * 2
}

fn square(x: i32) -> i32 {
    x * x
}

// 接受函数指针作为参数的函数
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(f(arg))
}

// 返回函数指针的函数
fn get_operation(op: &str) -> Option<fn(i32) -> i32> {
    match op {
        "add_one" => Some(add_one),
        "multiply_by_two" => Some(multiply_by_two),
        "square" => Some(square),
        _ => None,
    }
}

// 函数指针与闭包的对比
fn process_with_function(value: i32, func: fn(i32) -> i32) -> i32 {
    func(value)
}

fn process_with_closure<F>(value: i32, func: F) -> i32
where
    F: Fn(i32) -> i32,
{
    func(value)
}

// 函数指针在数据结构中的使用
struct OperationPipeline {
    operations: Vec<fn(i32) -> i32>,
}

impl OperationPipeline {
    fn new() -> Self {
        Self {
            operations: Vec::new(),
        }
    }
    
    fn add_operation(&mut self, op: fn(i32) -> i32) {
        self.operations.push(op);
    }
    
    fn execute(&self, mut value: i32) -> i32 {
        for &op in &self.operations {
            value = op(value);
        }
        value
    }
}

fn demonstrate_function_pointers() {
    // 基本使用
    let result1 = do_twice(add_one, 5);
    println!("do_twice(add_one, 5) = {}", result1);
    
    let result2 = do_twice(square, 3);
    println!("do_twice(square, 3) = {}", result2);
    
    // 动态选择函数
    if let Some(op) = get_operation("multiply_by_two") {
        let result = op(10);
        println!("multiply_by_two(10) = {}", result);
    }
    
    // 函数指针与闭包的对比
    let func_result = process_with_function(5, add_one);
    let closure_result = process_with_closure(5, |x| x + 1);
    
    println!("Function result: {}", func_result);
    println!("Closure result: {}", closure_result);
    
    // 两者都可以传递函数
    let func_as_closure = process_with_closure(5, add_one);
    println!("Function as closure: {}", func_as_closure);
    
    // 但闭包捕获环境时不能转换为函数指针
    let y = 10;
    // let closure_with_env = |x| x + y;
    // process_with_function(5, closure_with_env); // 错误!
    
    // 使用操作管道
    let mut pipeline = OperationPipeline::new();
    pipeline.add_operation(add_one);
    pipeline.add_operation(multiply_by_two);
    pipeline.add_operation(square);
    
    let final_result = pipeline.execute(2);
    println!("Pipeline result: {}", final_result);
    
    // 函数指针与C交互
    extern "C" {
        fn qsort(
            base: *mut std::ffi::c_void,
            nmemb: usize,
            size: usize,
            compar: unsafe extern "C" fn(*const std::ffi::c_void, *const std::ffi::c_void) -> i32,
        );
    }
    
    // 在实际代码中,我们会在这里定义比较函数并调用qsort
    println!("FFI example ready (commented out for safety)");
}

返回闭包

由于闭包的类型是匿名的,直接返回闭包需要一些特殊的处理技巧。

rust 复制代码
// 返回闭包的基本方法:使用Box
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}

// 返回捕获环境的闭包
fn make_adder(y: i32) -> Box<dyn Fn(i32) -> i32> {
    Box::new(move |x| x + y)
}

// 使用impl Trait返回闭包(更现代的写法)
fn returns_closure_impl() -> impl Fn(i32) -> i32 {
    |x| x * 2
}

fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
    move |x| x * factor
}

// 复杂的闭包返回类型
fn create_complex_closure(operation: &str) -> Box<dyn Fn(i32, i32) -> i32> {
    match operation {
        "add" => Box::new(|a, b| a + b),
        "multiply" => Box::new(|a, b| a * b),
        "max" => Box::new(|a, b| a.max(b)),
        _ => Box::new(|a, b| a - b),
    }
}

// 闭包在迭代器转换中的应用
fn create_transformer() -> impl Fn(Vec<i32>) -> Vec<String> {
    |numbers| {
        numbers
            .into_iter()
            .map(|n| format!("Value: {}", n))
            .collect()
    }
}

// 高级模式:返回实现了多个trait的闭包
fn create_advanced_closure() -> Box<dyn Fn(i32) -> i32 + Send + Sync> {
    Box::new(|x| x * x)
}

fn demonstrate_returning_closures() {
    // 基本闭包返回
    let closure1 = returns_closure();
    println!("returns_closure(5) = {}", closure1(5));
    
    let closure2 = returns_closure_impl();
    println!("returns_closure_impl(5) = {}", closure2(5));
    
    // 捕获环境的闭包
    let add_five = make_adder(5);
    println!("make_adder(5)(10) = {}", add_five(10));
    
    let times_three = make_multiplier(3);
    println!("make_multiplier(3)(4) = {}", times_three(4));
    
    // 动态选择闭包
    let operations = ["add", "multiply", "max", "unknown"];
    for &op in &operations {
        let closure = create_complex_closure(op);
        let result = closure(5, 3);
        println!("{}: 5 {} 3 = {}", op, 
                 match op {
                     "add" => "+",
                     "multiply" => "*", 
                     "max" => "max",
                     _ => "-",
                 }, 
                 result);
    }
    
    // 在数据处理中使用返回的闭包
    let transformer = create_transformer();
    let numbers = vec![1, 2, 3, 4, 5];
    let strings = transformer(numbers);
    println!("Transformed: {:?}", strings);
    
    // 多线程中的闭包使用
    let advanced_closure = create_advanced_closure();
    let handle = std::thread::spawn(move || {
        println!("Advanced closure in thread: {}", advanced_closure(6));
    });
    
    handle.join().unwrap();
    
    // 闭包组合
    fn compose<F, G, A, B, C>(f: F, g: G) -> impl Fn(A) -> C
    where
        F: Fn(A) -> B,
        G: Fn(B) -> C,
    {
        move |x| g(f(x))
    }
    
    let add_one = |x| x + 1;
    let multiply_by_two = |x| x * 2;
    let add_then_multiply = compose(add_one, multiply_by_two);
    
    println!("compose(add_one, multiply_by_two)(3) = {}", add_then_multiply(3));
}

函数和闭包的高级模式

让我们探索一些函数和闭包的高级使用模式。

rust 复制代码
// 闭包状态机
fn create_counter() -> impl FnMut() -> i32 {
    let mut count = 0;
    move || {
        count += 1;
        count
    }
}

// 记忆化(缓存)闭包
fn create_cached_closure<F, T, U>(f: F) -> impl FnMut(T) -> U
where
    F: Fn(T) -> U,
    T: std::hash::Hash + Eq + Clone,
    U: Clone,
{
    use std::collections::HashMap;
    
    let mut cache = HashMap::new();
    move |arg| {
        if let Some(result) = cache.get(&arg) {
            result.clone()
        } else {
            let result = f(arg.clone());
            cache.insert(arg, result.clone());
            result
        }
    }
}

// 策略模式使用闭包
struct Processor<F> {
    strategy: F,
}

impl<F> Processor<F>
where
    F: Fn(i32) -> i32,
{
    fn new(strategy: F) -> Self {
        Self { strategy }
    }
    
    fn process(&self, value: i32) -> i32 {
        (self.strategy)(value)
    }
}

// 闭包作为回调
struct EventHandler<F> {
    callback: F,
}

impl<F> EventHandler<F>
where
    F: Fn(&str),
{
    fn new(callback: F) -> Self {
        Self { callback }
    }
    
    fn handle_event(&self, event: &str) {
        (self.callback)(event);
    }
}

// 高阶函数:接受闭包并返回闭包的函数
fn create_logging_wrapper<F, T, U>(f: F, name: &'static str) -> impl Fn(T) -> U
where
    F: Fn(T) -> U,
    T: std::fmt::Debug,
    U: std::fmt::Debug,
{
    move |arg| {
        println!("Calling {} with argument: {:?}", name, arg);
        let result = f(arg);
        println!("{} returned: {:?}", name, result);
        result
    }
}

fn demonstrate_advanced_patterns() {
    // 状态闭包
    let mut counter = create_counter();
    println!("Counter: {}", counter());
    println!("Counter: {}", counter());
    println!("Counter: {}", counter());
    
    // 记忆化
    let expensive_calculation = |x: i32| {
        println!("Performing expensive calculation for {}", x);
        x * x
    };
    
    let mut cached_calc = create_cached_closure(expensive_calculation);
    println!("First call: {}", cached_calc(5));  // 计算
    println!("Second call: {}", cached_calc(5)); // 从缓存获取
    
    // 策略模式
    let double_processor = Processor::new(|x| x * 2);
    let increment_processor = Processor::new(|x| x + 1);
    
    println!("Double processor: {}", double_processor.process(5));
    println!("Increment processor: {}", increment_processor.process(5));
    
    // 事件处理
    let event_handler = EventHandler::new(|event| {
        println!("Event received: {}", event);
    });
    
    event_handler.handle_event("button_click");
    event_handler.handle_event("key_press");
    
    // 高阶函数
    let add_one = |x| x + 1;
    let logged_add_one = create_logging_wrapper(add_one, "add_one");
    
    let result = logged_add_one(5);
    println!("Final result: {}", result);
    
    // 闭包组合和管道
    let functions: Vec<Box<dyn Fn(i32) -> i32>> = vec![
        Box::new(|x| x + 1),
        Box::new(|x| x * 2),
        Box::new(|x| x - 3),
    ];
    
    let initial_value = 5;
    let final_value = functions.into_iter().fold(initial_value, |acc, f| f(acc));
    println!("Pipeline result: {}", final_value);
    
    // 条件闭包执行
    fn execute_if<F>(condition: bool, true_func: F, false_func: F) -> impl FnOnce() -> ()
    where
        F: FnOnce() -> (),
    {
        move || {
            if condition {
                true_func();
            } else {
                false_func();
            }
        }
    }
    
    let success_handler = || println!("Operation succeeded!");
    let error_handler = || println!("Operation failed!");
    
    let operation = execute_if(true, success_handler, error_handler);
    operation();
}

总结

本章深入探讨了Rust的高级特性,包括:

  1. 不安全Rust:如何在必要时绕过编译器的安全检查,同时保持代码的整体安全性
  2. 高级trait:关联类型、默认泛型参数、完全限定语法、父trait和newtype模式
  3. 高级类型:类型别名、never type、动态大小类型和Sized trait
  4. 高级函数和闭包:函数指针、返回闭包的各种技巧以及函数式编程模式

这些高级特性让Rust能够在保持内存安全的同时,提供系统级编程所需的底层控制能力。理解这些特性对于编写高效、安全的Rust代码至关重要,特别是在构建库、框架和系统软件时。

记住,不安全Rust应该谨慎使用,并且总是要将其封装在安全的抽象中。高级trait和类型系统特性则可以帮助我们构建更表达力强、更安全的API。函数和闭包的高级用法则让我们能够编写更灵活、更可复用的代码。

相关推荐
G探险者2 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
Tony Bai2 小时前
Go 在 Web3 的统治力:2025 年架构与生态综述
开发语言·后端·架构·golang·web3
乄bluefox2 小时前
Reactor 中的 doOnError 与 doOnCancel
java·reactor·rea
源码之家2 小时前
基于Python房价预测系统 数据分析 Flask框架 爬虫 随机森林回归预测模型、链家二手房 可视化大屏 大数据毕业设计(附源码)✅
大数据·爬虫·python·随机森林·数据分析·spark·flask
CoderYanger2 小时前
B.双指针——3194. 最小元素和最大元素的最小平均值
java·开发语言·数据结构·算法·leetcode·职场和发展·1024程序员节
SalvoGao2 小时前
Python学习 | 怎么理解epoch?
数据结构·人工智能·python·深度学习·学习
Charles_go2 小时前
C#中级、double和decimal有什么区别
开发语言·c#
程序猿20232 小时前
项目结构深度解析:理解Spring Boot项目的标准布局和约定
java·spring boot·后端
思成不止于此2 小时前
深入理解 C++ 多态:从概念到实现的完整解析
开发语言·c++·笔记·学习·多态·c++40周年