You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中获取对象堆地址及智能指针工作机制相关疑问

Rust中获取对象堆地址及智能指针工作机制相关疑问

嘿,作为Rust新手能盯着内存地址琢磨智能指针的工作原理,这个学习方式超棒!我来帮你把这些疑惑逐个理清楚:

核心问题:怎么获取Rc包裹的堆上原始对象的地址

你其实已经找对方法啦!Rc::as_ptr(&rc_new)返回的就是堆上原始Node对象的真实地址——从你的输出里能看到,as_ptr打印的第二个地址0x600003099230,和直接打印rc_new的结果完全一致。这是因为Rc<T>实现了Deref trait,当你直接打印rc_new时,Rust会自动解引用到内部的堆对象,所以显示的就是堆地址,这两个方式得到的都是你要找的原始对象地址。

拆解你代码里的各个输出含义

我们逐个看你的打印结果:

  1. 开头的0x16aeba9d8:这是你栈上创建的Node对象n的地址。此时n还在栈上,直到你调用Rc::new(n),Rc才会把这个Node对象复制到堆上,所以之后的堆地址变成了0x600003099230。
  2. new 0x16aebaaa8 0x600003099230:
    • 第一个地址0x16aebaaa8是Rc智能指针本身在栈上的地址——每个Rc实例都是栈上的一个小结构体,里面存着指向堆对象的指针、强引用计数、弱引用计数。
    • 第二个地址就是堆上Node的地址,和前面说的一致。
  3. 你代码里的clone打印写错啦!应该是println!("clone {:p} {:p}", &rc_clone, rc_clone);,你现在写的还是&rc_new,所以栈地址和new的一样。改完之后你会看到,&rc_clone是另一个栈地址,但rc_clone打印的堆地址还是和之前的一样——这就是Rc的核心:多个栈上的Rc实例共享同一个堆对象。
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:18:05