先设计一个自引用类型,然后能过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,自引用没有发生错乱了,随着结构体做相应的变动了。