关于Rust中的自引用:差之毫厘?!

先设计一个自引用类型,然后能过std:mem:swap来观察其变化:

一、为什么自引用没有出现预期的问题

use std::mem;

#[derive(Debug)]
struct SelfRef{
    name : String,
    ptr: *const String
}
fn main() {
    let name_a = String::from("hello a");
    let ptr_a = & name_a as *const String;
    
    let name_b = String::from("hello_b");
    let ptr_b = & name_b as *const String;
    
    let mut self_a = SelfRef{name:name_a,ptr:ptr_a};//这种不是自引用
    let mut self_b = SelfRef{name:name_b,ptr:ptr_b};//这种不是自引用
    
    println!("--------------before swap :----------------------");
    println!("self_a :{:?} ",self_a);
    println!("self_b :{:?} ",self_b);
    println!("a pointer -> self_a: {:p} self_a_inner_ptr:{:p} ",&self_a,self_a.ptr);
    println!("b pointer -> self_b: {:p} self_b_inner_ptr:{:p} ",&self_b,self_b.ptr);
    
    println!("a value   -> self_a.name: {:?} self_a_inner_ptr -> value :{:?} ",&self_a.name,unsafe{&*self_a.ptr});
    println!("b value   -> self_b.name: {:?} self_b_inner_ptr -> value :{:?} ",&self_b.name,unsafe{&*self_b.ptr});

    mem::swap(&mut self_a, &mut self_b);

    println!("-------------after swap :------------------------");
    println!("self_a :{:?} ",self_a);
    println!("self_b :{:?} ",self_b);
    println!("a pointer -> self_a: {:p} self_a_inner_ptr:{:p} ",&self_a,self_a.ptr);
    println!("b pointer -> self_b: {:p} self_b_inner_ptr:{:p} ",&self_b,self_b.ptr);
    println!("a value   -> self_a.name: {:?} self_a_inner_ptr -> value :{:?} ",&self_a.name,unsafe{&*self_a.ptr});
    println!("b value   -> self_b.name: {:?} self_b_inner_ptr -> value :{:?} ",&self_b.name,unsafe{&*self_b.ptr});
    

}

看看输出:

Running `target/debug/playground`

Standard Output

--------------before swap :----------------------
self_a :SelfRef { name: "hello a", ptr: 0x7ffdd46d6480 } 
self_b :SelfRef { name: "hello_b", ptr: 0x7ffdd46d6498 } 
a pointer -> self_a: 0x7ffdd46d64b0 self_a_inner_ptr:0x7ffdd46d6480 
b pointer -> self_b: 0x7ffdd46d64f0 self_b_inner_ptr:0x7ffdd46d6498 
a value   -> self_a.name: "hello a" self_a_inner_ptr -> value :"hello a" 
b value   -> self_b.name: "hello_b" self_b_inner_ptr -> value :"hello_b" 
-------------after swap :------------------------
self_a :SelfRef { name: "hello_b", ptr: 0x7ffdd46d6498 } 
self_b :SelfRef { name: "hello a", ptr: 0x7ffdd46d6480 } 
a pointer -> self_a: 0x7ffdd46d64b0 self_a_inner_ptr:0x7ffdd46d6498 
b pointer -> self_b: 0x7ffdd46d64f0 self_b_inner_ptr:0x7ffdd46d6480 
a value   -> self_a.name: "hello_b" self_a_inner_ptr -> value :"hello_b" 
b value   -> self_b.name: "hello a" self_b_inner_ptr -> value :"hello a" 

奇怪的是,并没有出现swap后self_a.ptr所指向的内容为“hello_a”,这个是什么原因呢?

二、 调整代码,重现自引用的问题

我们调整一下:

use std::mem;

#[derive(Debug)]
struct SelfRef{
    name : String,
    ptr: *const String
}
fn main() {
    let name_a = String::from("hello a");
    let mut self_a = SelfRef{name:name_a,ptr: std::ptr::null()};//先赋值
    self_a.ptr = &self_a.name as *const String;//再对字段进行赋值,变成真正自引用

    let name_b = String::from("hello b");
    let mut self_b = SelfRef{name:name_b,ptr:std::ptr::null()};
    self_b.ptr = &self_b.name as *const String;

    println!("--------------before swap :----------------------");
    println!("self_a :{:?} ",self_a);
    println!("self_b :{:?} ",self_b);
    println!("a pointer -> self_a: {:p} self_a_inner_ptr:{:p} ",&self_a,self_a.ptr);
    println!("b pointer -> self_b: {:p} self_b_inner_ptr:{:p} ",&self_b,self_b.ptr);
    
    println!("a value   -> self_a.name: {:?} self_a_inner_ptr -> value :{:?} ",&self_a.name,unsafe{&*self_a.ptr});
    println!("b value   -> self_b.name: {:?} self_b_inner_ptr -> value :{:?} ",&self_b.name,unsafe{&*self_b.ptr});

    mem::swap(&mut self_a, &mut self_b);

    println!("-------------after swap :------------------------");
    println!("self_a :{:?} ",self_a);
    println!("self_b :{:?} ",self_b);
    println!("a pointer -> self_a: {:p} self_a_inner_ptr:{:p} ",&self_a,self_a.ptr);
    println!("b pointer -> self_b: {:p} self_b_inner_ptr:{:p} ",&self_b,self_b.ptr);
    println!("a value   -> self_a.name: {:?} self_a_inner_ptr -> value :{:?} ",&self_a.name,unsafe{&*self_a.ptr});
    println!("b value   -> self_b.name: {:?} self_b_inner_ptr -> value :{:?} ",&self_b.name,unsafe{&*self_b.ptr});
}

再看输出:

--------------before swap :----------------------
self_a :SelfRef { name: "hello a", ptr: 0x7ffc13a4c808 } 
self_b :SelfRef { name: "hello b", ptr: 0x7ffc13a4c858 } 
a pointer -> self_a: 0x7ffc13a4c800 self_a_inner_ptr:0x7ffc13a4c808 
b pointer -> self_b: 0x7ffc13a4c850 self_b_inner_ptr:0x7ffc13a4c858 
a value   -> self_a.name: "hello a" self_a_inner_ptr -> value :"hello a" 
b value   -> self_b.name: "hello b" self_b_inner_ptr -> value :"hello b" 
-------------after swap :------------------------
self_a :SelfRef { name: "hello b", ptr: 0x7ffc13a4c858 } 
self_b :SelfRef { name: "hello a", ptr: 0x7ffc13a4c808 } 
a pointer -> self_a: 0x7ffc13a4c800 self_a_inner_ptr:0x7ffc13a4c858 
b pointer -> self_b: 0x7ffc13a4c850 self_b_inner_ptr:0x7ffc13a4c808 
a value   -> self_a.name: "hello b" self_a_inner_ptr -> value :"hello a" 
b value   -> self_b.name: "hello a" self_b_inner_ptr -> value :"hello b" 

这下,就看出来了,swap后,self_a结构体中ptr字段指向的内容还是“hello_a”,和原来的预期保持一致了。

三、新的问题来了,如何Pin住?

use std::mem;
use std::{marker::PhantomPinned, pin::Pin};


#[derive(Debug)]
struct SelfRef{
    name : String,
    ptr: *const String,
    _marker: PhantomPinned, //必须打上PIN的标识
}

fn main(){
    let name_a = String::from("hello a");
    let mut self_a = SelfRef{name:name_a,ptr: std::ptr::null(),_marker: PhantomPinned};
    let mut self_a = unsafe { Pin::new_unchecked(&mut self_a)};
    let mut self_a = unsafe { &mut self_a.get_unchecked_mut() }; 
    self_a.ptr = &self_a.name as *const String;
    

    let name_b = String::from("hello b");
    let mut self_b = SelfRef{name:name_b,ptr: std::ptr::null(),_marker: PhantomPinned};
    let mut self_b = unsafe { Pin::new_unchecked(&mut self_b)};
    let mut self_b = unsafe { &mut self_b.get_unchecked_mut() }; 
    self_b.ptr = &self_b.name as *const String;

    
    println!("--------------before swap <PIN>:----------------------");
    println!("self_a :{:?} ",self_a);
    println!("self_b :{:?} ",self_b);
    println!("a pointer -> self_a: {:p} self_a_inner_ptr:{:p} ",&self_a,self_a.ptr);
    println!("b pointer -> self_b: {:p} self_b_inner_ptr:{:p} ",&self_b,self_b.ptr);
    
    println!("a value   -> self_a.name: {:?} self_a_inner_ptr -> value :{:?} ",&self_a.name,unsafe{&*self_a.ptr});
    println!("b value   -> self_b.name: {:?} self_b_inner_ptr -> value :{:?} ",&self_b.name,unsafe{&*self_b.ptr});

    mem::swap(&mut self_a, &mut self_b);

    println!("-------------after swap <PIN>:------------------------");
    println!("self_a :{:?} ",self_a);
    println!("self_b :{:?} ",self_b);
    println!("a pointer -> self_a: {:p} self_a_inner_ptr:{:p} ",&self_a,self_a.ptr);
    println!("b pointer -> self_b: {:p} self_b_inner_ptr:{:p} ",&self_b,self_b.ptr);
    println!("a value   -> self_a.name: {:?} self_a_inner_ptr -> value :{:?} ",&self_a.name,unsafe{&*self_a.ptr});
    println!("b value   -> self_b.name: {:?} self_b_inner_ptr -> value :{:?} ",&self_b.name,unsafe{&*self_b.ptr});

看看输出:

Standard Output

--------------before swap <PIN>:----------------------
self_a :SelfRef { name: "hello a", ptr: 0x7fff17773368, _marker: PhantomPinned } 
self_b :SelfRef { name: "hello b", ptr: 0x7fff177733c8, _marker: PhantomPinned } 
a pointer -> self_a: 0x7fff17773398 self_a_inner_ptr:0x7fff17773368 
b pointer -> self_b: 0x7fff177733f8 self_b_inner_ptr:0x7fff177733c8 
a value   -> self_a.name: "hello a" self_a_inner_ptr -> value :"hello a" 
b value   -> self_b.name: "hello b" self_b_inner_ptr -> value :"hello b" 
-------------after swap <PIN>:------------------------
self_a :SelfRef { name: "hello b", ptr: 0x7fff177733c8, _marker: PhantomPinned } 
self_b :SelfRef { name: "hello a", ptr: 0x7fff17773368, _marker: PhantomPinned } 
a pointer -> self_a: 0x7fff17773398 self_a_inner_ptr:0x7fff177733c8 
b pointer -> self_b: 0x7fff177733f8 self_b_inner_ptr:0x7fff17773368 
a value   -> self_a.name: "hello b" self_a_inner_ptr -> value :"hello b" 
b value   -> self_b.name: "hello a" self_b_inner_ptr -> value :"hello a" 

检查一下,PIN的效果出来了,有了PIN,自引用没有发生错乱了,随着结构体做相应的变动了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值