Rust 学习-什么时候将数据放到堆

陈蕃
• 阅读 1648

什么时候将数据放到堆

认识所有权, 生命周期与引用有效性, 智能指针 这三章是相关联的,所有权和生命周期确保数据的有效性,智能指针数据存放在堆上,指针在栈上。

书中建议

  • 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
  • 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
  • 当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候

个人理解如果是用户自定义结构体数据数据较大或者在运行时才能确定大小的数据,多个不同作用域需要共享数据时建议放在堆中。Vec中的数据就是放在堆中。

使用场景

使用Rust开发一个小工具时,发现经常有调用clone方法的场景。在读取文件数据解析创建了一个结构体,然后放到一个Vec中,在某个地方需要获取一些数据修改一些值,然后保持到另一个Vec中。这时在Vec中取出了值修改数据,clone一份保存,虽然到了需求。但是我想的是两个Vec都是同一份数据,只是两个Vec数量不一样,这时就需要将对象保持到堆中了。

// 场景 多个 C 对象需要共享  A, B 数据,对A需要有修改权限
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct A {
    name: String,
}
impl Drop for A {
    fn drop(&mut self) {
        println!("A drop: {}", self.name);
    }
}

impl Drop for B {
    fn drop(&mut self) {
        println!("B drop: {}", self.name);
    }
}
#[derive(Debug)]
struct B {
    name: String,
}
#[derive(Debug)]
struct C {
    list_a: Vec<Rc<RefCell<A>>>,
    list_b: Vec<Rc<B>>,
}

#[test]
fn test_rc() {
    let mut c = C {
        list_a: Vec::new(),
        list_b: Vec::new(),
    };
    let a = Rc::new(RefCell::new(A {
        name: String::from("zhang"),
    }));
    let b = Rc::new(B {
        name: String::from("wu"),
    });
    println!("a ptr: {:p}", a);
    println!("b ptr: {:p}", b);
    c.list_a.push(a);
    c.list_b.push(b);
    f2(&c);
    c.list_b.push(Rc::new(B {
        name: String::from("li"),
    }));
    println!("{:?}", c);
}

fn f2(c: &C) {
    let mut c2 = C {
        list_a: Vec::new(),
        list_b: Vec::new(),
    };

    for c1a in c.list_a.iter() {
        println!("a ptr: {:p}", *c1a);
        let mut a = (*c1a).borrow_mut();
        a.name = String::from("我改了");
        c2.list_a.push(Rc::clone(c1a));
    }
    for c1b in c.list_b.iter() {
        println!("b ptr: {:p}", *c1b);
        c2.list_b.push(Rc::clone(c1b));
    }
    println!("{:?}", c2);
}

上面代码两个 C都指向了堆上的AB,在f2中修改C中的A数据,并将指针放入了第二个C中。在代码的运行结果可以发现AB都没有clone的动作,两个C对象都是指向的同一份数据。这里的数据不支持多线共享,需要在多线程下共享数据需要使用到Mutex<T>Arc<T>

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
4年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Easter79 Easter79
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这