借用与引用实战

Rust 借用与引用实战

引言

借用是 Rust 中使用值而不获取其所有权的方式。通过引用,我们可以在不转移所有权的情况下访问数据。Rust 的借用检查器确保引用始终有效。

借用规则

借用遵循两条关键规则:

  1. 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
  2. 引用必须总是有效的

基础示例

rust 复制代码
fn main() {
    let mut s = String::from("hello");
    
    // 不可变借用
    let r1 = &s;
    let r2 = &s;
    println!("{} and {}", r1, r2);
    
    // 可变借用
    let r3 = &mut s;
    r3.push_str(", world");
    println!("{}", r3);
}

复杂案例:实现一个缓存系统

下面实现一个支持并发访问的缓存系统,展示借用在实际场景中的应用。

rust 复制代码
use std::collections::HashMap;
use std::hash::Hash;

struct Cache<K, V> 
where 
    K: Eq + Hash + Clone,
    V: Clone,
{
    store: HashMap<K, V>,
    max_size: usize,
    access_count: HashMap<K, usize>,
}

impl<K, V> Cache<K, V> 
where
    K: Eq + Hash + Clone,
    V: Clone,
{
    fn new(max_size: usize) -> Self {
        Cache {
            store: HashMap::new(),
            max_size,
            access_count: HashMap::new(),
        }
    }
    
    // 不可变借用:读取缓存
    fn get(&mut self, key: &K) -> Option<&V> {
        if let Some(count) = self.access_count.get_mut(key) {
            *count += 1;
        }
        self.store.get(key)
    }
    
    // 可变借用:插入或更新缓存
    fn insert(&mut self, key: K, value: V) {
        if self.store.len() >= self.max_size && !self.store.contains_key(&key) {
            self.evict_least_used();
        }
        
        self.store.insert(key.clone(), value);
        self.access_count.insert(key, 1);
    }
    
    // 淘汰最少使用的项
    fn evict_least_used(&mut self) {
        if let Some((&ref key, _)) = self.access_count
            .iter()
            .min_by_key(|(_, &count)| count) 
        {
            let key_to_remove = key.clone();
            self.store.remove(&key_to_remove);
            self.access_count.remove(&key_to_remove);
        }
    }
    
    // 不可变借用:获取统计信息
    fn stats(&self) -> CacheStats {
        let total_accesses: usize = self.access_count.values().sum();
        CacheStats {
            size: self.store.len(),
            max_size: self.max_size,
            total_accesses,
        }
    }
    
    // 不可变借用:检查是否包含键
    fn contains(&self, key: &K) -> bool {
        self.store.contains_key(key)
    }
    
    // 可变借用:清空缓存
    fn clear(&mut self) {
        self.store.clear();
        self.access_count.clear();
    }
}

struct CacheStats {
    size: usize,
    max_size: usize,
    total_accesses: usize,
}

impl CacheStats {
    fn print(&self) {
        println!("缓存统计:");
        println!("  当前大小: {}/{}", self.size, self.max_size);
        println!("  总访问次数: {}", self.total_accesses);
        println!("  使用率: {:.2}%", 
                 (self.size as f64 / self.max_size as f64) * 100.0);
    }
}

fn demonstrate_cache() {
    let mut cache = Cache::new(3);
    
    // 插入数据
    cache.insert("user:1", "Alice");
    cache.insert("user:2", "Bob");
    cache.insert("user:3", "Charlie");
    
    // 读取数据(不可变借用)
    if let Some(user) = cache.get(&"user:1") {
        println!("找到用户: {}", user);
    }
    
    // 再次访问增加计数
    cache.get(&"user:1");
    cache.get(&"user:2");
    
    // 插入新数据,触发淘汰
    cache.insert("user:4", "David");
    
    // 检查缓存内容
    println!("user:3 还在缓存中吗? {}", cache.contains(&"user:3"));
    
    // 打印统计信息
    cache.stats().print();
}

// 演示引用的生命周期
fn reference_lifetime_demo() {
    let data = vec![1, 2, 3, 4, 5];
    
    // 借用切片
    let slice = &data[1..4];
    println!("切片内容: {:?}", slice);
    
    // 同时存在多个不可变引用
    let ref1 = &data;
    let ref2 = &data;
    let ref3 = &data;
    
    println!("Sum via ref1: {}", ref1.iter().sum::<i32>());
    println!("Len via ref2: {}", ref2.len());
    println!("First via ref3: {}", ref3[0]);
}

// 实现一个需要精确控制借用的数据结构
struct BorrowTracker<T> {
    data: T,
    borrow_count: usize,
    mut_borrowed: bool,
}

impl<T> BorrowTracker<T> {
    fn new(data: T) -> Self {
        BorrowTracker {
            data,
            borrow_count: 0,
            mut_borrowed: false,
        }
    }
    
    fn borrow(&mut self) -> Result<&T, String> {
        if self.mut_borrowed {
            return Err("数据已被可变借用".to_string());
        }
        self.borrow_count += 1;
        Ok(&self.data)
    }
    
    fn borrow_mut(&mut self) -> Result<&mut T, String> {
        if self.borrow_count > 0 {
            return Err(format!("数据已被借用 {} 次", self.borrow_count));
        }
        if self.mut_borrowed {
            return Err("数据已被可变借用".to_string());
        }
        self.mut_borrowed = true;
        Ok(&mut self.data)
    }
    
    fn release(&mut self) {
        if self.borrow_count > 0 {
            self.borrow_count -= 1;
        }
    }
    
    fn release_mut(&mut self) {
        self.mut_borrowed = false;
    }
}

fn demonstrate_borrow_tracking() {
    let mut tracker = BorrowTracker::new(vec![1, 2, 3]);
    
    // 不可变借用
    match tracker.borrow() {
        Ok(data) => println!("借用成功: {:?}", data),
        Err(e) => println!("借用失败: {}", e),
    }
    
    tracker.release();
    
    // 可变借用
    match tracker.borrow_mut() {
        Ok(data) => {
            data.push(4);
            println!("可变借用成功,修改后: {:?}", data);
        },
        Err(e) => println!("可变借用失败: {}", e),
    }
    
    tracker.release_mut();
}

fn main() {
    demonstrate_cache();
    println!("\n---\n");
    reference_lifetime_demo();
    println!("\n---\n");
    demonstrate_borrow_tracking();
}

借用与迭代器

迭代器是借用的典型应用场景:

rust 复制代码
fn iterator_borrowing() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // iter() 创建不可变引用的迭代器
    let sum: i32 = numbers.iter().sum();
    println!("和: {}", sum);
    
    // 原始数据仍然可用
    println!("原始数据: {:?}", numbers);
    
    // 过滤和映射
    let even_squares: Vec<i32> = numbers
        .iter()
        .filter(|&&x| x % 2 == 0)
        .map(|&x| x * x)
        .collect();
    
    println!("偶数的平方: {:?}", even_squares);
}

总结

借用和引用是 Rust 实现内存安全的关键机制。通过编译时检查,Rust 确保引用的正确使用,避免数据竞争和悬垂引用。

相关推荐
The 旺5 小时前
【Rust实战】打造内存安全的网络代理:深入异步IO与并发编程
网络·安全·rust
RustCoder7 小时前
RustNet:使用 Rust 开发的跨平台网络监控工具
安全·rust·开源
Xxtaoaooo7 小时前
Rust Actix-web框架源码解析:基于Actor模型的高性能Web开发
rust·源码分析·高性能·并发安全·actix-web
鼓掌MVP7 小时前
Rust Web实战:构建高性能并发工具的艺术
开发语言·前端·rust·异步编程·内存安全·actix-web·高性能web服务
盒马盒马7 小时前
Rust:函数与控制流
开发语言·网络·rust
编码追梦人18 小时前
深耕 Rust:核心技术解析、生态实践与高性能开发指南
开发语言·后端·rust
蒙娜丽宁19 小时前
Rust 并发编程进阶:线程模型、通道通信与异步任务对比分析
开发语言·网络·rust
分布式存储与RustFS1 天前
RustFS:MinIO的“平替”还是“乱杀”?
python·rust·对象存储·minio·存储·企业存储·rustfs
ai安歌1 天前
【Rust编程:从新手到大师】Rust概述
开发语言·后端·rust