文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
7.7 指针
很多时候,指针是相对宽泛概念,并非特指 原始指针 (raw-pointer)。以 引用 (reference)为例,经编译检查后,卸去职责,在底层指令层面,与原始指针无异。
引用和原始指针是独立对象,间接( *p
)操作目标。透过指针修改目标时,无需声明指针自身可变(mut),除非指针打算改变自己的指向。
raw-pointer reference ===================+================= *const T &T *mut T &mut T
原始指针
原始指针也分可变和不可变。无论读写都不安全,须自行负责。
fn main() { let mut x = 100; let r: *mut i32 = &mut x; unsafe { *r += 1; assert_eq!(*r, 101); } let r: *const i32 = &x; assert_eq!(unsafe{ *r }, 101); }
可以和引用相互转换。
fn main() { let mut x = 100; let r = &mut x; // 引用转指针必然是安全的。 let p = r as *mut i32; assert_eq!(unsafe{ *p }, x); // 指针转回引用就未必安全了。 let r2: &mut i32 = unsafe{ &mut *p }; // unsafe{ & *p } -> &i32 *r2 += 1; assert_eq!(x, 101); }
可通过 usize
转换实现指针运算。也正因如此,指向无法保证。
use std::mem::size_of_val; fn main() { let mut x = [1, 2, 3, 4]; let mut p: *mut i32 = &mut x[0]; // 指针自身和目标都可变。 unsafe { assert_eq!(*p, 1); p = ((p as usize) + size_of_val(&x[0])) as *mut i32; // p++ *p += 10; assert_eq!(*p, 12); } }
原始指针不参与对象生命周期,有可能成为悬垂指针。
#[derive(Debug)] struct Data { x: i32, } impl Drop for Data { fn drop(&mut self) { println!("Dropping!"); } } fn main() { let d = Data{ x: 10 }; let p = &d as *const Data; { let _d2 = d; // move!!! } // drop!!! unsafe { println!("{:p}, {:?}", p, *p); } }
$ cargo r Finished dev [unoptimized + debuginfo] target(s) in 0.06s Running `target/debug/demo` Dropping! 0x7ffe5b385654, Data { x: 10 } # 虽然能返回内容,但这只是因为是栈内存未被覆盖的缘故。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论