[英]What are the differences between `*const T` and *mut T` raw pointers?
我正在编写一些不安全的Rust代码,因此我需要知道*const T
和*mut T
的确切区别。 我认为它像&T
和&mut T
(即你只是无法通过突变T
通过&T
,周期),但是这似乎并没有这样的情况!
例如,指针包装器NonNull<T>
的定义如下( source ):
pub struct NonNull<T: ?Sized> {
pointer: *const T,
}
但是,可以通过as_ptr
从此包装器获得*mut T
,其定义如下:
pub const fn as_ptr(self) -> *mut T {
self.pointer as *mut T
}
该功能甚至没有标记为unsafe
! 我不允许从&T
强制转换为&mut T
(有充分的理由!),但是显然可以强制转换这样的指针。
Nomicon在有关方差的章节中提到*const T
和*mut T
的方差不同:
*const T
:协变*mut T
:不变
这是指针类型之间的唯一区别吗? 在我看来,这很奇怪。
指针类型之间到底有什么区别? *mut T
没有*const T
限制吗? 如果差异很小,那么在语言中同时包含两种指针类型的其他原因是什么?
*const T
和*mut T
之间的区别 毫不奇怪,可变和const原始指针之间的主要区别是,取消引用它们会产生可变的还是不变的位置表达式。 取消引用const指针会产生一个不变的位置表达式 ,取消引用一个可变指针会产生一个可变的表达式 。 根据语言参考 ,可变性的含义是:
对于要分配,可变借用,隐式可变借用或绑定到包含
ref mut
mutt的模式的场所表达式,它必须是可变的。
正如您已经指出的,const和可变指针之间的另一个区别是类型的差异,我认为这就是全部。
您可以在安全代码中将*const T
转换为*mut T
,因为一旦取消引用指针,可变性的差异就变得很重要,并且反引用原始指针无论如何都是不安全的操作。 如果不强制转换为可变指针,则无法获得const指针指向的内存的可变位置表达式。
Rust可以对原始指针的可变性更加放松的原因之一是,与引用相比,它没有对原始指针的别名进行任何假设。 请参阅取消原始指针的语义是什么? 有关更多详细信息。
NonNull
使用*const T
? NonNull
指针类型用作Box
和Rc
等智能指针的构造块。 这些类型公开了遵循常规Rust引用规则的接口-只有通过拥有或可变引用智能指针本身,才可以更改指针,并且只能通过借用智能指针本身来获得对指针的共享引用。 。 这意味着这些类型是协变的是安全的,只有在NonNull
是协变的情况下才有可能,这又意味着我们需要使用*const T
而不是*mut T
。
让我们考虑一下替代方案。 如果只有一个指针类型,则必须是可变指针–否则我们将无法通过原始指针进行任何修改。 但是该指针类型也需要是协变的,因为否则我们将无法构建协变智能指针类型。 (始终可以通过在结构中包含PhantomData<some invariant type>
来放弃协方差,但是一旦您的结构之一被其成员变为不变,就无法再次使其协变。)由于可变引用是不变的,此虚构指针类型的行为将有些令人惊讶。
另一方面,具有两种不同的指针类型可以很好地类似于引用:const指针是协变的,并且对不可变的位置表达式的引用,就像共享引用一样;可变指针是不变的,并且对可变的位置表达式的引用,就像可变的一样参考。
我只能推测这是否是设计该语言的真正原因,因为我找不到有关该主题的任何讨论,但是这个决定对我来说似乎并不合理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.