* const T和* mut T原始指针有什么区别? [英] What are the differences between `*const T` and *mut T` raw pointers?

查看:300
本文介绍了* const T和* mut T原始指针有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一些不安全的Rust代码,因此我需要知道*const T*mut T之间的确切区别.我假设它就像&T&mut T(即,您不能通过&T在句点之间将T突变),但是事实并非如此!

I'm writing some unsafe Rust code so I need to know the exact differences between *const T and *mut T. I assumed that it's like &T and &mut T (i.e. you just can't mutate T through &T, period), but that doesn't seem to be the case!

例如,指针包装器NonNull<T>的定义如下(

For example, the pointer wrapper NonNull<T> is defined as follows (source):

pub struct NonNull<T: ?Sized> {
    pointer: *const T,
}

但是,可以通过*mut T. rel ="noreferrer"> as_ptr ,它的定义为:

However, it's possible to obtain a *mut T from this wrapper via as_ptr, which is just defined as:

pub const fn as_ptr(self) -> *mut T {
    self.pointer as *mut T
}

该功能甚至未标记为unsafe!我不允许从&T强制转换为&mut T(有充分的理由!),但是显然可以像这样强制转换指针.

The function is not even marked as unsafe! I am not allowed to cast from &T to &mut T (for a good reason!), but apparently casting pointers like that is fine.

Nomicon在有关差异的章节中提到,*const T*mut T的方差不同:

The Nomicon mentions in the chapter about variance that *const T and *mut T differ in variance:

  • *const T:协变
  • *mut T:不变
  • *const T: covariant
  • *mut T: invariant

这是指针类型之间的唯一区别吗?在我看来,这很奇怪...

Is this the only difference between the pointer types? That would seem strange to me...

指针类型之间到底有什么区别?*const T没有*mut T的限制吗?如果差异很小,那么在语言中同时包含两种指针类型的其他原因是什么?

What exactly are the differences between the pointer types? Are there restrictions for *const T that *mut T doesn't have? If the differences are minimal: what are additional reasons to include both pointer types in the language?

推荐答案

*const T*mut T

之间的差异

可变和const原始指针之间的主要区别不足为奇,即对它们的取消引用会产生可变的还是不变的位置表达式.取消引用const指针会产生不可变的位置表达式,取消引用可变指针会产生可变指针.根据语言参考, 的含义如下:

Differences between *const T and *mut T

The main difference between mutable and const raw pointer is, not surprisingly, whether dereferencing them yields a mutable or immutable place expression. Dereferencing a const pointer yields an immutable place expression, dereferencing a mutable pointer yields a mutable one. The implications of mutability according to the language reference are this:

要将位置表达式分配,可变借用,隐式可变借用或绑定到包含ref mut的模式,它必须是可变的.

For a place expression to be assigned to, mutably borrowed, implicitly mutably borrowed, or bound to a pattern containing ref mut it must be mutable.

正如您已经提到的,const和可变指针之间的另一个区别是类型的差异,我认为这就是全部.

The other difference between const and mutable pointers is the variance of the types, as you already noted, and I think that's all there is.

您可以使用安全代码将*const T强制转换为*mut T,因为一旦取消引用指针,可变性的差异就变得很重要,并且反引用原始指针无论如何都是不安全的操作.如果不强制转换为可变指针,则无法获得const指针指向的内存的可变位置表达式.

You can cast a *const T to a *mut T in safe code, since the difference in mutability only becomes relevant once you dereference the pointers, and dereferencing a raw pointer is an unsafe operation anyway. Without casting to a mutable pointer, you cannot get a mutable place expression for the memory a const pointer points to.

Rust可以对原始指针的可变性更加放松的一个原因是,与引用相比,它没有对原始指针的别名进行任何假设.请参阅取消引用原始指针的语义是什么?详细信息.

One reason Rust can be a bit more relaxed about mutability for raw pointers is that it does not make any assumptions about aliasing for raw pointers, in contrast to references. See What are the semantics for dereferencing raw pointers? for further details.

NonNull指针类型用作BoxRc等智能指针的构造块.这些类型公开了遵循常规Rust引用规则的接口-只有通过拥有或可变引用智能指针本身,才可以更改指针,并且只能通过借用智能指针本身来获得对指针的共享引用. .这意味着这些类型是协变的是安全的,只有在NonNull是协变的情况下才有可能,这又意味着我们需要使用*const T而不是*mut T.

The NonNull pointer type is used as a building block for smart pointers like Box and Rc. These types expose interfaces that follow the usual Rust rules for references – mutation of the pointee is only possible through ownership of or a mutable reference to the smart pointer itself, and a shared reference to the pointee can only be obtained by borrowing the smart pointer itself. This means it is safe for these types to be covariant, which is only possible if NonNull is covariant, which in turn means we need to use a *const T rather than a *mut T.

让我们考虑一下替代方案.如果只有一个指针类型,则必须是可变指针–否则我们将无法通过原始指针进行任何修改.但是该指针类型也需要是协变的,因为否则我们将无法构建协变智能指针类型. (总是可以通过在结构中包含PhantomData<some invariant type>来放弃协方差,但是一旦您的结构由其成员之一变为不变,就无法再次使其协变.)由于可变引用是不变的,因此行为这种虚构的指针类型会有些令人惊讶.

Let's think about the alternative. If there was only a single pointer type, it would necessarily need to be the mutable pointer – otherwise we'd be unable to modify anything through a raw pointer. But that pointer type would also need to be covariant, since otherwise we'd be unable to build covariant smart pointer types. (It's always possible to give up covariance by including a PhantomData<some invariant type> in a struct, but once your struct is rendered invariant by one of its members, there is no way to make it covariant again.) Since mutable references are invariant, the behaviour of this imaginary pointer type would be somewhat surprising.

另一方面,具有两种不同的指针类型,可以很好地类似于引用:const指针是协变的,并且可以对不可变的位置表达式进行引用,就像共享引用一样;可变指针是不变的,并且可以对可变的位置表达式进行引用,就像可变引用一样.

Having two different pointer types, on the other hand, allows for a nice analogy to references: const pointers are covariant and dereference to immutable place expressions, just like shared references, and mutable pointers are invariant and dereference to mutable place expressions, just like mutable references.

我只能推测这是否是设计语言的真正原因,因为我找不到关于该主题的任何讨论,但是这个决定对我来说似乎并不合理.

I can only speculate whether these were the actual reasons for the design of the language, since I could not find any discussion on the topic, but the decision doesn't seem unreasonable to me.

这篇关于* const T和* mut T原始指针有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆