Rust中获取对象堆地址及智能指针工作机制相关疑问
Rust中获取对象堆地址及智能指针工作机制相关疑问
嘿,作为Rust新手能盯着内存地址琢磨智能指针的工作原理,这个学习方式超棒!我来帮你把这些疑惑逐个理清楚:
核心问题:怎么获取Rc包裹的堆上原始对象的地址
你其实已经找对方法啦!Rc::as_ptr(&rc_new)返回的就是堆上原始Node对象的真实地址——从你的输出里能看到,as_ptr打印的第二个地址0x600003099230,和直接打印rc_new的结果完全一致。这是因为Rc<T>实现了Deref trait,当你直接打印rc_new时,Rust会自动解引用到内部的堆对象,所以显示的就是堆地址,这两个方式得到的都是你要找的原始对象地址。
拆解你代码里的各个输出含义
我们逐个看你的打印结果:
- 开头的
0x16aeba9d8:这是你栈上创建的Node对象n的地址。此时n还在栈上,直到你调用Rc::new(n),Rc才会把这个Node对象复制到堆上,所以之后的堆地址变成了0x600003099230。 new 0x16aebaaa8 0x600003099230:- 第一个地址
0x16aebaaa8是Rc智能指针本身在栈上的地址——每个Rc实例都是栈上的一个小结构体,里面存着指向堆对象的指针、强引用计数、弱引用计数。 - 第二个地址就是堆上
Node的地址,和前面说的一致。
- 第一个地址
- 你代码里的
clone打印写错啦!应该是println!("clone {:p} {:p}", &rc_clone, rc_clone);,你现在写的还是&rc_new,所以栈地址和new的一样。改完之后你会看到,&rc_clone是另一个栈地址,但rc_clone打印的堆地址还是和之前的一样——这就是Rc的核心:多个栈上的Rc实例共享同一个堆对象。 as_ptr 0x16aebaab8 0x600003099230:- 第一个地址是
as_ptr这个指针变量本身在栈上的地址, - 第二个地址才是它存储的堆对象地址,和之前的结果完全对应。
- 第一个地址是
关于String和Rc的额外疑惑
你测试String时发现Rc::new()似乎复制了堆数据,这是因为String本身的内存结构:
String是一个栈上的结构体,包含三个字段:指向堆上字节数据的指针、字符串长度、容量。- 当你调用
Rc::new(my_string)时,Rc会把整个String结构体复制到堆上——此时堆上有一个String实例,它又指向另一个堆区域的字节数据,相当于多了一层间接性,看起来像是复制了数据,但其实字节数据本身没有被复制,只是String结构体被移到了堆上。
如果想更高效地共享字符串的字节数据,推荐用Rc<str>:
use std::rc::Rc; let s = String::from("hello"); let rc_str: Rc<str> = s.into(); // 直接把String转成Rc<str>,不会复制字节数据 println!("{:p}", rc_str); // 这就是堆上字节数据的地址
这种方式会让Rc直接指向堆上的字节切片,没有额外的String结构体层,完全避免了不必要的复制。
补充:如果结构体有堆指向的字段怎么办?
如果你的Node结构体里的right字段有值(比如Some(Rc<Node>)),要获取它指向的堆地址,可以这样做:
if let Some(right_rc) = &n.right { println!("Right node heap address: {:p}", Rc::as_ptr(right_rc)); }
内容来源于stack exchange
相关产品推荐
相关产品推荐

