Rust 写时克隆智能指针 Cow

Rust中Cow类型:写时克隆智能指针详解 智能指针是现代编程语言中管理内存的重要抽象,其中写时克隆(Copy-On-Write)是一种常见的内存优化技术。Rust语言通过Cow(Clone-On-Write)类型实现了这一模式,它能够在需要修改数据时才进行克隆,避免不必要的内存分配。这种机制特别适合处理字符串解析、配置管理和模板引擎等场景,能显著提升性能。Cow通过枚举设计区分借用和自有数据,结合ToOwned等trait保证类型安全,是Rust零成本抽象原则的典型体现。在实际工程中,合理使用Cow可以优化字符串处理性能,实现零拷贝解析,是高性能R 阅读详情

Rust 写时克隆智能指针 Cow

Cow(Clone-On-Write,写时克隆)智能指针在 Rust 所有智能指针中是最尤为特殊的,它的作用是在只读场景下避免不必要的内存克隆,仅在需要修改时才惰性克隆数据,本文将从核心原理、基本用法、实战场景等维度带你掌握 Cow 智能指针的使用。

为什么需要 Cow 智能指针?

在日常开发中,我们经常会遇到这样的场景:一个函数接收一段数据(如字符串、切片),大多数情况下仅需要只读访问,但偶尔需要对数据进行修改后返回。此时会面临一个两难选择:

  • 若函数参数和返回值都使用借用类型(如 &str、&[T]),则无法在函数内修改数据( Rust 借用规则禁止可变借用与不可变借用共存);
  • 若函数参数和返回值都使用所有权类型(如 String、Vec<T>),则无论是否需要修改,都必须克隆数据,造成不必要的内存分配和性能开销。

Cow 智能指针的出现,正是为了解决这个痛点。它的核心思想是:只读时借用,修改时克隆。当数据无需修改时,Cow 以借用的形式持有数据,不占用额外内存;当需要修改数据时,Cow 才会克隆一份数据并获得其所有权,再进行修改操作。这种惰性克隆的机制,既保证了内存安全,又最大化提升了性能。

底层原理

Cow 本质上是一个枚举类型,定义在 std::borrow 模块中,其源码核心结构如下(简化版):

pub enum Cow<'a, B: 'a + ToOwned + ?Sized> {
    // 持有一份不可变借用,生命周期与 'a 绑定
    Borrowed(&'a B),
    // 持有一份拥有所有权的数据,类型是 B 的所有权形式(由 ToOwned  trait 定义)
    Owned(<B as ToOwned>::Owned),
}

要理解这个枚举,我们需要重点关注两个约束和其特性:

核心约束解析

  • B: 'a:借用的数据生命周期必须不短于 Cow 实例的生命周期,避免悬垂引用;
  • B: ToOwned:这是 Cow 实现“写时克隆”的核心特征,它定义了如何将借用类型 &B 转换为所有权类型 <B as ToOwned>::Owned。Rust 标准库为常见类型(如 str、[T])默认实现了 ToOwned,例如 str 的 ToOwned 实现会返回 String,[T] 的 ToOwned 实现会返回 Vec<T>;
  • B: ?Sized:支持动态大小类型(如 str、[T]),这也是 Cow 能灵活处理字符串、切片的关键。

核心特性:Deref 实现与惰性克隆

Cow 实现了 Deref 特征,这意味着我们可以像使用普通引用一样使用 Cow 实例,无需手动解包,就能直接调用底层数据的方法。例如 Cow<str> 可以直接调用 len()、contains() 等 str 的方法,实现了“透明访问”。

而写时克隆主要通过 to_mut() 方法来实现:

  • 若 Cow 当前处于 Borrowed 状态(持有借用数据),调用 to_mut() 会克隆借用的数据,将自身状态切换为 Owned,然后返回一份可变引用;
  • 若 Cow 当前已处于 Owned 状态(持有所有权数据),调用 to_mut() 会直接返回数据的可变引用,无需克隆。

此外,Cow 还提供了 into_owned() 方法,用于将 Cow 转换为所有权类型:若当前是 Borrowed 状态,则克隆数据;若已是 Owned 状态,则直接转移所有权,无额外开销。

Cow 基本用法

创建 Cow 实例

Cow 提供了多种创建方式,最常用的是 Cow::Borrowed()、Cow::Owned() 和 Cow::from()(自动推断状态):

use std::borrow::Cow;

fn main() {
    // 创建 Borrowed 状态的 Cow(借用字符串字面量)
    let borrowed_cow: Cow<'_, str> = Cow::Borrowed("hello rust");
    println!("Borrowed state: {}", borrowed_cow);

    // 创建 Owned 状态的 Cow(持有 String 所有权)
    let owned_cow: Cow<'_, str> = Cow::Owned(String::from("hello cow"));
    println!("Owned state: {}", owned_cow);
}

只读访问:零成本透明操作

由于 Cow 实现了 Deref 特征,我们可以直接对 Cow 实例进行只读操作,无需区分其状态,且无任何额外开销:

use std::borrow::Cow;

fn read_cow(cow: Cow<'_, str>) {
    // 直接调用 str 的方法,无需解包
    println!("长度: {}", cow.len());
    println!("是否包含 'rust': {}", cow.contains("rust"));
    println!("大写: {}", cow.to_uppercase());
}

fn main() {
    let borrowed_cow = Cow::Borrowed("hello rust");
    let owned_cow = Cow::Owned(String::from("hello cow"));

    read_cow(borrowed_cow); // 零分配,直接借用
    read_cow(owned_cow); // 直接访问自身持有的 String
}

修改操作:触发写时克隆

当需要修改 Cow 持有的数据时,调用 to_mut() 方法,Cow 会根据当前状态决定是否克隆数据:

use std::borrow::Cow;

fn modify_cow(cow: &mut Cow<'_, str>) {
    // 调用 to_mut(),若为 Borrowed 状态则克隆,转为 Owned 状态
    let mut_ref = cow.to_mut();
    // 修改数据
    mut_ref.push_str(" — modified");
}

fn main() {
    // 修改 Borrowed 状态的 Cow(触发克隆)
    let mut borrowed_cow = Cow::Borrowed("hello rust");
    println!("修改前(Borrowed): {}", borrowed_cow);
    modify_cow(&mut borrowed_cow);
    println!("修改后(Owned): {}", borrowed_cow);

    // 修改 Owned 状态的 Cow(不触发克隆)
    let mut owned_cow = Cow::Owned(String::from("hello cow"));
    println!("修改前(Owned): {}", owned_cow);
    modify_cow(&mut owned_cow);
    println!("修改后(Owned): {}", owned_cow);
}

运行结果可见:修改 Borrowed 状态的 Cow 时,会触发克隆并转为 Owned 状态;而修改已处于 Owned 状态的 Cow 时,直接修改数据,无克隆开销。

转换为所有权类型:into_owned()

使用 into_owned() 方法可将 Cow 转为对应的所有权类型,根据当前状态决定是否克隆:

use std::borrow::Cow;

fn main() {
    let borrowed_cow: Cow<'_, str> = Cow::Borrowed("hello rust");
    let owned_str1 = borrowed_cow.into_owned();
    println!("borrowed -> owned: {}", owned_str1);

    let owned_cow: Cow<'_, str> = Cow::Owned(String::from("hello cow"));
    let owned_str2 = owned_cow.into_owned();
    println!("owned -> owned: {}", owned_str2);
}

实战场景

场景一:条件修改数据

当函数需要根据条件修改数据,且大多数情况下无需修改时,使用 Cow 可避免不必要的克隆。例如,字符串规范化,确保路径以 “/” 结尾:

use std::borrow::Cow;

/// 确保路径以 "/" 结尾,无需修改时返回借用,需要修改时返回所有权
fn ensure_trailing_slash(path: &str) -> Cow<'_, str> {
    if path.ends_with('/') {
        // 无需修改,返回 Borrowed 状态,零分配
        Cow::Borrowed(path)
    } else {
        // 需要修改,克隆并追加 "/",返回 Owned 状态
        let mut owned_path = path.to_owned();
        owned_path.push('/');
        Cow::Owned(owned_path)
    }
}

fn main() {
    let path1 = "/var/log/";
    let cow1 = ensure_trailing_slash(path1);
    // 模式匹配判断状态
    let cow1_state = match &cow1 {
        Cow::Borrowed(_) => "Borrowed",
        Cow::Owned(_) => "Owned",
    };
    println!("path1: {}, 状态: {}", cow1, cow1_state);

    let path2 = "/home/user";
    let cow2 = ensure_trailing_slash(path2);
    // 模式匹配判断状态
    let cow2_state = match &cow2 {
        Cow::Borrowed(_) => "Borrowed",
        Cow::Owned(_) => "Owned",
    };
    println!("path2: {}, 状态: {}", cow2, cow2_state);
}

这个场景中,当路径已符合规范时,无需分配内存;当且仅当需要修改时才克隆,这极大的提升了性能。

场景二:优化 API 设计

在设计 API 时,使用 Cow 作为参数或返回值,可以让函数同时支持借用类型和所有权类型,提升 API 的灵活性,同时避免用户手动克隆。例如,一个处理文本的函数:

use std::borrow::Cow;

/// 处理文本:包含 "error" 则替换为 "warning",否则返回原内容
fn process_text(text: Cow<'_, str>) -> Cow<'_, str> {
    if text.contains("error") {
        // 需要修改,返回 Owned 状态
        Cow::Owned(text.replace("error", "warning"))
    } else {
        // 无需修改,返回原状态(可能是 Borrowed 或 Owned)
        text
    }
}

fn main() {
    // 传入借用类型(&str)
    let borrowed_text = "something error happened";
    let result1 = process_text(Cow::from(borrowed_text));
    println!("result1: {}", result1);

    // 传入所有权类型(String)
    let owned_text = String::from("no error here");
    let result2 = process_text(Cow::from(owned_text));
    println!("result2: {}", result2);
}

这种设计无需为两种类型单独写函数,既简化了 API,又避免了用户在无需修改时的克隆操作。

场景三:切片处理

Cow<'a, [T]> 在处理字节缓冲区,比如网络数据包、文件解析时极为有用,可避免不必要的 Vec 克隆。例如,一个简易的协议解析器:

use std::borrow::Cow;

/// 处理数据包:0x01 表示压缩数据(需解压),否则使用原始数据
fn process_packet(packet: &[u8]) -> Cow<'_, [u8]> {
    if packet.is_empty() {
        return Cow::Borrowed(packet);
    }

    match packet[0] {
        0x01 => {
            // 模拟解压逻辑,生成新的 Vec<u8>(触发克隆)
            let decompressed = vec![10, 20, 30];
            println!("数据包已解压");
            Cow::Owned(decompressed)
        }
        _ => {
            // 原始数据,直接借用(跳过协议头)
            println!("使用原始数据包");
            Cow::Borrowed(&packet[1..])
        }
    }
}

fn main() {
    // 压缩数据包(0x01 为协议头)
    let compressed_packet = &[0x01, 0xFF, 0xEE];
    let data1 = process_packet(compressed_packet);
    println!("处理后数据1: {:?}", data1);

    // 原始数据包(0x00 为协议头)
    let raw_packet = &[0x00, 1, 2, 3];
    let data2 = process_packet(raw_packet);
    println!("处理后数据2: {:?}", data2);
}

注意事项与常见误区

区分 Cow 与其他智能指针

很多开发者会将 Cow 与 Rc、Arc 混淆,其实它们的核心定位完全不同:

  • Cow:核心是“写时克隆”,不负责共享所有权,仅用于优化“只读多、修改少”场景的内存开销;
  • Rc/Arc:核心是“共享所有权”,通过引用计数管理内存,适用于多所有者场景(Rc 单线程,Arc 多线程);

另外,Rc::make_mut() 和 Arc::make_mut() 也有写时克隆语义,但它们带有引用计数开销,而 Cow 无此开销。

避免滥用 Cow

Cow 并非万能的,以下场景不适合使用 Cow:

  • 频繁修改数据的场景:若数据需要频繁修改,Cow 会频繁触发克隆,反而不如直接使用所有权类型(如 String、Vec<T>)高效;
  • 需要共享所有权的场景:Cow 不支持多所有者,此时应使用 Rc 或 Arc;
  • 非动态大小类型场景:若数据类型是 Sized(如 i32、struct),使用 Cow 无意义,直接使用引用或所有权类型即可。

总结

掌握 Cow 的关键的是:理解其“只读借用、修改克隆”的核心逻辑,明确其适用场景,避免与 Rc、Arc 等智能指针混淆。在实际开发中,当你需要处理“可能修改、但大多数时候只读”的数据时,Cow 往往是最优选择。

【Rust】写时复制Cow 写时复制(Copy on Write)技术是一种程序中的优化策略,多应用于读多写少的场景。主要思想是创建对象的时候不立即进行复制,而是先引用(借用)原有对象进行大量的读操作,只有进行到少量的写操作的时候,才进行复制操作,将原有对象复制后再写入。这样的好处是在读多写少的场景下,减少了复制操作,提高了性能。 Rust中对应这种思想的是智能指针Cow<T>,定义如下: pub enum Co... 阅读详情

相关推荐

Python3.8下MvCameraControl.dll加载失败?3种方法彻底解决FileNotFoundError

本文针对Python3.8及以上版本在Windows平台调用MvCameraControl.dll时出现的FileNotFoundError问题,深入剖析了其根源在于Python 3.8引入的DLL加载安全机制变更。文章提供了三种核心解决方案:显式指定DLL完整路径、使用os.add_dll_directory()添加可信目录,以及利用ctypes的winmode参数进行精细控制,并给出了工程化封装建议,帮助开发者彻底解决此兼容性问题。

weixin_29093017的博客 193

Rust Cow智能指针:写时克隆机制与性能优化实践

在编程语言的内存管理中,智能指针是一种重要的抽象工具,它通过自动化资源管理来提升代码的安全性和效率。Rust语言的所有权系统是其核心特性之一,而Cow(Clone-on-Write)智能指针则在此基础上实现了写时克隆的延迟决策机制。其技术价值在于优化读多写少的场景,通过避免不必要的内存复制来提升性能。Cow利用Borrow和ToOwned trait在借用和所有权之间建立类型安全的桥梁,使得在大多数只读操作中可以零成本地使用引用,仅在需要修改时才执行克隆操作。这种机制在处理配置数据、字符串变换和解析器等应用

weixin_42617406的博客 529

工程经验分享:PCIE(1)

本文介绍AXI Bridge For Pcie Express Gen3 Subsystem 的使用方法。这个IP兼具简单与实用性,将PCIE协议层实现于内部,仅留出AXI接口供开发者使用。开发者不需要处理复杂的PCIE协议数据,只需要对AXI总线有所了解即可,十分符合Xilinx一贯的开发风格。本文无关PCIE协议本身,仅分享实用性的工程经验,以PCIE IP为核心,一步一步搭建一个简单的子系统,以此说明用法。文中所有内容均已通过项目检验。

weixin_42415266的博客 3844

Rust智能指针Box、Rc、Cow详解:内存分配与所有权实战

Rust的所有权与借用模型是内存安全的基石,但面对堆上动态大小数据、多处共享以及避免不必要克隆等场景,仅靠基础规则往往难以表达。智能指针应运而生:Box将数据放入堆中,以固定大小指针解决递归类型和大对象拷贝问题;Rc通过引用计数允许多个所有者共享数据,但只适用于单线程;Cow提供“写时克隆”语义,让返回值能借用就借用,需修改才复制。理解三者各自解决的问题与底层Deref/Drop机制,能显著减少编译错误并优化性能。无论你是刚入门所有权,还是正在实践中排查内存问题,深入掌握这些智能指针都是Rust开发的关键一

weixin_32821533的博客 245

阿里云学生机2核4G,30分钟搞定DNF台服联机(CentOS 7.6保姆级教程)

本文提供阿里云学生机2核4G搭建DNF台服联机的详细教程,涵盖服务器选购、网络配置、服务端部署及客户端联机设置。通过CentOS 7.6系统优化和端口配置,30分钟内即可完成搭建,适合学生和技术爱好者低成本实现游戏联机体验。

weixin_42537919的博客 362

避坑指南:Zephyr RTOS与nRF Connect SDK环境搭建常见错误及解决方案

本文详细解析了Zephyr RTOS与nRF Connect SDK环境搭建过程中的常见错误及解决方案,涵盖网络问题、代理设置、SEGGER Embedded Studio配置、分支切换等关键环节。针对开发者实际遇到的痛点问题,提供了一系列实用技巧和深度排错方法,帮助高效完成NCS开发环境部署。

weixin_28685287的博客 172

Rustlings 智能指针实战:从 Box 到 Rc、Arc 与 Cow 的四道经典练习详解

Rust 的智能指针是"持有内存地址并引用其他数据,但额外携带元数据与能力"的特殊变量,与只借用数据的引用(reference)形成鲜明对比——它通常**拥有**所指向的数据。本文基于 rustlings 仓库中 [exercises/19_smart_pointers](https://link.gitcode.com/i/316e8d3ac6450d3ccc76215b2ca03460) 章节

gitblog_00218的博客 818

【ComfyUI 基础教程】ComfyUI 局部重绘工作流教程

本篇指南将带你了解 ComfyUI 中的局部重绘工作流,并带你完成一个局部重绘的示例,以及遮罩编辑器的使用等。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 303

std1.97.1——borrow模块细览

Rust学习笔记

qq_51180928的博客 81

【原创教程】汇川H5U入门教案第二课

定时器指令IN输入能流从OFF变为ON时,定时器启动计时,输出Q为ON,IN输入能流从ON变为OFF时,在IN保持为OFF期间,定时器的运行时间是PT参数指定的时间,定时器定时时间达到PT参数指定的时间后,Q变为OFF。IN输入能流为ON时,ET输出值为0,IN从ON变为OFF时,在定时器计时运行期间,ET输出当前的计时时间,定时器计时时间到达PT参数指定的时间后,ET值保持。IN输入能流为ON时,在定时器计时运行期间,ET输出当前的计时时间,定时器计时时间到达PT参数指定的时间后,ET值保持;

Qinmingyue13的博客 2486

PointNet++改进策略目录

后续我将如何使用文章中创新点加入的PointNet++中代码实现部分进行更新。

u012901740的博客 2198

Rust 智能指针详解:从 C 引用语义到 Box、Rc、Arc、RefCell 与 Cow 的全面指南

> 本文是《Rust for C# Programmers》(仓库中 `csharp-book`)第 7 章「Ownership and Borrowing」的进阶子章节,面向已经理解 Rust 所有权与借用规则的 C# 开发者。你将系统掌握 `Box<T>`、`Rc<T>`、`Arc<T>`、`Cell<T>`、`RefCell<T>`、`Cow<'a, T>` 六种核心智能指针的适用场景、线程

gitblog_01126的博客 138

Unreal5从入门到精通之如何实现移动端触屏滑动手势

随着移动设备的普及,越来越多的游戏和应用选择在移动平台上发布。Unreal Engine 5(UE5)作为一款强大的游戏引擎,提供了丰富的工具和功能,帮助开发者打造出色的移动体验。UE5不仅提升了图形质量,还大幅简化了开发流程,使得开发者能够更专注于游戏设计和用户体验。在移动游戏中,触屏滑动手势是用户与应用互动的主要方式之一。然而,许多开发者在实现这些功能时常常遇到困难。为了填补这一知识空白,本篇文章将详细介绍如何在UE5中实现移动端触屏滑动手势,帮助你从入门到精通,提升你的开发技能。

TxNet 1138

Rust中的Clone trait与拷贝机制详解

在编程语言中,值拷贝是基础且重要的操作,涉及栈内存与堆内存的数据复制机制。Rust通过Clone trait提供了显式的拷贝控制,与隐式的Copy trait形成互补。理解浅拷贝与深拷贝的区别对内存管理至关重要——浅拷贝仅复制栈数据(如指针),而深拷贝会递归复制堆数据。在系统编程领域,合理选择拷贝策略能显著提升性能,特别是在处理大型数据结构或并发场景时。Rust的智能指针(Rc/Arc)和写时复制(Cow)等机制,为解决数据共享与拷贝的矛盾提供了优雅方案。本文以Rust的Clone实现为例,深入探讨了内存安

weixin_42116058的博客 193

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

RustTraining 智能指针与内部可变性完全指南:从 Box/Rc/Arc 到 Pin 投影与 ManuallyDrop

> 本文源自 RustTraining 仓库《Rust Patterns & Engineering How-Tos》系列([rust-patterns-book](https://link.gitcode.com/i/55b9c05cd8741764f8e24c6901a821e2))第 9 章「Smart Pointers and Interior Mutability」。你将系统掌握 Rus

gitblog_00550的博客 392

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Rust Cow(deepseek)

(Clone On Write) 是 Rust 标准库中的一个智能指针,主要目的是在需要时才进行数据克隆,从而提高性能。它是 中的一个枚举类型。 核心特性 1. 两个变体 :包含对数据的不可变引用 :包含数据的所有权 2. 主要使用场景 避免不必要的克隆操作 实现写时复制模式 在处理可能为引用或拥有的数据时提供灵活性 实际示例 基础使用 字符串处理示例 解析器示例 常用方法 1. - 获取可变引用(必要时克隆) 2. - 转换为拥有的数据 3. / - 检查状态 实际应用场景

唐装鼠的主页 574

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

rust语言学习笔记(指针十一)Cow<T>(写时克隆)

摘要: Rust 的 Cow(写时克隆)智能指针通过延迟克隆优化内存使用,适用于读多写少的场景。它允许数据在只读时直接借用,仅在需要修改时克隆。核心优势在于零成本抽象,避免不必要的内存分配。 关键点: 内存效率:Cow 仅在修改时克隆,如处理字符串、切片时减少分配。 适用场景:配置文件解析、反序列化等读多写少操作,如 Cow<str> 和 Cow<[u8]> 的应用。 惰性克隆:通过 to_mut() 方法实现按需克隆,如批量处理负数时仅克隆一次。 与可变性工具对比:Cow 解决借用/所有权选择,而 Cel

咸甜适中 275

rust进阶教程 (1)

本文介绍了 Rust 中的智能指针及其内存管理机制。主要内容包括: Box<T>:最简单的堆分配智能指针,用于处理递归类型和大数据所有权转移 Rc<T>:引用计数智能指针,允许多个所有者共享数据(仅限单线程) RefCell<T>:实现内部可变性模式,允许在不可变引用下修改数据 组合使用示例:展示了如何结合 Rc 和 RefCell 构建可变共享所有权的数据结构(如树形结构) 这些智能指针扩展了 Rust 的所有权系统,提供了更灵活的内存管理方式,同时保持编译时的安全性检

a181001_的博客 318

深入浅出 Rust Cow:在“写时复制”中追求极致性能

Rust 的Cow完美体现了“按需分配”的思想。它通过生命周期和枚举,在底层实现了极其灵活的内存策略。在性能敏感的应用中,合理使用Cow往往是减少 CPU 和内存占用的关键招式。

咚为 980

Rust的Cow智能指针:延迟分配与性能优化的艺术

Cow是Rust中一种用于精细化管理内存分配的优化策略。它不是一个零成本抽象,而是一个基于“读取远多于写入”假设的性能工具。真正的专家级实践在于识别场景:当你的代码路径存在明显的“只读热路径”和“偶发写入冷路径”时,Cow就是避免昂贵克隆、提升系统吞吐量的利器。在反序列化、配置管理、数据清洗等领域,Cow是实现“零开销”与“必要开销”动态平衡的优雅解决方案。🚀。

2501_94042748的博客 1019

Rust中的智能指针 Cow

理解: 名称 Cow 参数'a为生命周期参数B为基础参数Rust规定 枚举 都必须至少有一个变体Cow 拥有两个变体:表示对数据的不可变借用。:表示拥有数据的克隆副本。用法:处理可能来自借用或拥有的数据,避免非必要克隆。Cow 实现了Deref需要可变性时,Cow会自动克隆(写时)

qq_73775399的博客 787

【rCore OS 开源操作系统】Rust 智能指针

在 Rust 中,“智能指针”是指那些实现了**特定智能行为**的指针类型。这些智能行为通常包括**内存管理**、**生命周期跟踪**以及**所有权转移等**。

碳基蒟蒻Serio的博客 1203

Rust智能指针:Box、Rc与Cow核心解析

智能指针是现代编程语言中管理内存安全的核心机制,通过封装原始指针并附加元数据和行为,实现编译时的内存安全检查。Rust语言通过所有权系统和智能指针的结合,提供了零成本抽象的内存安全保障。Box<T>用于堆内存分配和独占所有权场景,Rc<T>实现引用计数的共享所有权,而Cow<T>则采用写时复制策略优化性能。这些智能指针在系统编程、数据结构实现和性能敏感场景中具有重要价值,特别是在处理递归类型、共享数据和避免不必要拷贝等场景时表现出色。掌握Rust的Box、Rc和Cow等智能指针的区别与使用场景,是编写高效安

weixin_29290863的博客 191

Rust编程学习 - 为什么说Cow 代表的是Copy-On-Write, 即“写时复制技术”,它是一种高效的 资源管理手段

大家需要注意的是,这个self的类型是&Self,不是&mutSelf。但我们同时还需要使用这个共享引用self来修改引用计数的值。所以这个成员必须是具有内部可变性的。反之,如果它们是普通的整数,那么我们就要 求使用&mutSelf类型来调用clone方法,然而一般情况下,我们都会需要多个Rc 指 针指向同一块内存区域,引用计数值是共享的。如果存在多个&mut 型指针指向引用计数值的 话,则违反了Rust 内存安全的规则。因 此 ,Rc 智能指针的实现,必须使用“内部可变性”功能。

2301_79651252的博客 1048

rust实战系列九十五:Cow

它对指向的数据可能“拥有所有权”,或者可能“不拥有所有权”。在C++语境中,Cow代表的是Copy-On-Write,即“写时复制技术”。况,有一些性能损失。Cow类型还实现了Deref trait,所以当我们需要调用类型T的成员函数的时候,*&T的类型一定是T,而&*T的类型。·如果返回类型指定为&str类型,那么需要新分配内存的时候,会出现生命周期。而需要提醒大家注意的是,“取引用”操作符,如&、&mut,是不允许重载的。更重要的是,读者需要理解,在某些情况下,编译器帮我们插入了自动deref的。

Mr_Roki的博客 1071

Rust智能指针:Box、Rc与Cow的核心原理与实践

智能指针是现代编程语言中管理内存安全与灵活性的重要工具。通过引用计数、写时复制等机制,智能指针在保持内存安全的同时,提供了比原始指针更高级的抽象能力。Rust语言中的Box、Rc和Cow三种智能指针分别解决了堆内存确定性释放、多所有权共享和惰性克隆等关键问题。在系统编程、高性能计算等领域,合理使用智能指针能显著提升内存使用效率,避免常见的内存泄漏问题。本文以Rust为例,深入解析Box的堆分配控制、Rc的引用计数实现,以及Cow的写时复制优化,帮助开发者掌握这些核心工具在递归数据结构、配置管理等真实场景中的

weixin_28339967的博客 229
上一篇: Rust 并发同步:Mutex 与 RwLock 智能指针
下一篇: Rust Default 特征详解:轻松实现类型默认值
Rust研习社
博客等级 码龄11年 52粉丝 84原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值