本文转载自微信公众号《董泽润的技术笔记》,作者董泽润。转载本文请联系董泽润技术笔记公众号。熟悉c++的一定知道shared_ptr、unique_ptr,Rust还有智能指针Box、Rc、Arc、RefCell等。本文分享Box的底层实现Box会在堆上分配空间,存储T值,并返回对应的指针。同时,Box还实现了traitDeref解引用和Drop解构。当Box离开作用域时,它会自动释放空间);}在堆上分配变量0x11223344,所谓装箱,Java同学一定不陌生。挂载docker,使用rust-gdb查看程序集实现Dumpofassemblercodeforfunctionhello_cargo::main:0x000055555555bdb0<+0>:sub$0x18,%rsp0x000055555555bdb4<+4>:movl$0x11223344,0x14(%rsp)+2db5bc<555>:MOV$0x4,%ESI0x00005555555555555555555555555555555555555555>:MOV%RSI,%rdi0x000055555555555555555555555555555555555555555555555555555555555BDC4<+20>:CallQ0X5555555555B5B00x00555555555555555555555555555BRIS%rcx,%rax0x000055555555bdcf<+31>:movl$0x11223344,(%rcx)0x000055555555bdd5<+37>:mov%rax,0x8(%rsp)0x000055555555bdda<+42>5di5050fdd0%+45:d5q25<45:d5q255:dcore255:dcore255:dcore::drop_in_place>>0x000055555555bde4<+52>:add$0x18,%rsp0x000055555555bde8<+56>:retqEndofassemblerdump。两个关键点,alloc::alloc::exchange_malloc在堆上分配内存空间,然后将0x11223344存入这个malloc的地址。函数结束时,将地址传给core::ptr::drop_in_place释放,因为编译器知道类型是alloc::boxed::Box,会使用Box对应drop函数简单看一下这个例子。盒子并不神秘。它对应于汇编实现,与普通指针没有区别。所有约束都是编译时行为所有权。fnmain(){letx=Box::new(String::from("Rust"));lety=*x;println!("xis{}",x);}在此示例中,字符串被装箱。其实不用这么写,因为String本身就是一种广义上的智能指针。这个例子会报错3|lety=*x;|--valuemovedhere4|println!("xis{}",x);|^valueborrowedhereaftermove*x对应解引用后的String,赋给y时执行move语义,所有权没有了,所以后续的println无法打印xlety=&*x;您可以采用字符串的不可变引用来修复pubstructBox(Unique,A);以上是Box的定义。可以看到它是一个元组结构,有两个泛型参数:T代表任意类型,A代表内存分配器。A是标准库中的Gloal默认值。其中,T有一个泛型约束?Sized,也就是说类型的大小在编译时可能知道也可能不知道。当然,一般用于不知道大小的场景,很少存储int#[stable(feature="rust1",since="1.0.0")]unsafeimpl<#[may_dangle]T:?Sized,A:Allocator>DropforBox{fndrop(&mutself){//FIXME:Donothing,dropiscurrentlyperformedbycompiler.}}This是由Drop实现的,源码中有提到,由编译器实现#[stable(feature="rust1",since="1.0.0")]implDerefforBox{typeTarget=T;fnderef(&self)->&T{&**self}}#[stable(feature="rust1",since="1.0.0")]implDerefMutforBox{fnderef_mut(&mutself)->&mutT{&mut**self}}实现Deref来定义解引用行为,DerefMut是变量解引用。所以*x对应操作*(x.deref())适用场景官网提到了以下三种场景。本质上,Box和普通的指针没有太大区别,所以不如Rc、Arc、RefCell好用。宽类型在编译时不知道大小,但是代码场景也需要确认类型大小当你有大量数据时,你需要移动所有权,又不想复制数据特征对象,或者叫dyn动态分配常用于在一个集合中存储不同的类型,或者参数指定不同类型的对象有一个链表实现enumList{Cons(i32,List),Nil,}上面的代码无法运行,以及原因很简单,这是一个递归定义。对应c代码也是不行的,我们一般要定义下一个类型为指针enumList{Cons(i32,Box),Nil,}usecrate::List::{Cons,Nil};fnmain(){letlist=Cons(1,Box::new(Cons(2,Box::new(Cons(3,Box::new(Nil))))));}官网给出的解决方案是转next变成一个指针Box,这是常识,没什么好说的