欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2024/1/18 编程问答 61 豆豆
生活随笔 收集整理的这篇文章主要介绍了 关于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,自引用没有发生错乱了,随着结构体做相应的变动了。

总结

以上是生活随笔为你收集整理的关于Rust中的自引用:差之毫厘?!的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。