gpt4 book ai didi

pointers - Box,ref和&和*之间的理解和关系

转载 作者:行者123 更新时间:2023-12-03 11:47:09 25 4
gpt4 key购买 nike

我对指针在Rust中的工作方式有些困惑。有refBox&*,我不确定它们如何协同工作。

这是我目前的理解:

  • Box并不是真正的指针-这是一种在堆上分配数据并在函数参数中传递大小不一的类型(尤其是特征)的方法。
  • ref用于模式匹配,以借用您匹配的内容,而不是获取它。例如,
    let thing: Option<i32> = Some(4);
    match thing {
    None => println!("none!"),
    Some(ref x) => println!("{}", x), // x is a borrowed thing
    }
    println!("{}", x + 1); // wouldn't work without the ref since the block would have taken ownership of the data
  • &用于借入(借入的指针)。如果我有一个函数fn foo(&self),那么我引用的是我自己,该引用将在该函数终止后到期,而不再保留调用者的数据。我还可以通过执行bar(&mydata)传递要保留所有权的数据。
  • *用于制作原始指针:例如let y: i32 = 4; let x = &y as *const i32。我了解C/C++中的指针,但是不确定如何将它与Rust的类型系统一起使用,以及如何安全地使用它们。我也不确定这种指针的用例是什么。另外,*符号可用于取消对事物的引用(什么事物,为什么?)。

  • 有人可以解释一下指向我的指针的第四种类型,并验证我对其他类型的理解是否正确吗?我还要感谢任何指出我没有提到的常见用例的人。

    最佳答案

    首先,列出的所有项目实际上都是不同的,即使它们与指针相关。 Box是库定义的智能指针类型; ref是用于模式匹配的语法; &是一个引用运算符,在引用类型中加倍作为标记。 *是一个取消引用运算符,在原始指针类型中的符号数量增加了一倍。请参阅下面的更多说明。

    Rust中有四种基本的指针类型,可以将它们分为两组-引用指针和原始指针:

    &T        - immutable (shared) reference
    &mut T - mutable (exclusive) reference

    *const T - immutable raw pointer
    *mut T - mutable raw pointer

    后两者之间的差异非常小,因为任何一个都可以不受任何限制地转换为另一个,因此那里的 const/ mut的区别主要是 Lint 。原始指针可以自由创建任何对象,例如,还可以凭空凭空创建整数。

    自然,对于引用不是这样-引用类型及其相互作用定义了Rust的主要功能之一:借用。引用在如何创建和何时创建,如何使用以及如何彼此交互方面有很多限制。作为返回,它们可以不使用 unsafe块来使用。但是,借用的确切内容及其工作方式超出了此答案的范围。

    引用和原始指针都可以使用 &运算符创建:
    let x: u32 = 12;

    let ref1: &u32 = &x;
    let raw1: *const u32 = &x;

    let ref2: &mut u32 = &mut x;
    let raw2: *mut u32 = &mut x;

    引用和原始指针都可以使用 *运算符取消引用,尽管对于原始指针来说,它需要一个 unsafe块:
    *ref1; *ref2;

    unsafe { *raw1; *raw2; }

    通常会省略取消引用运算符,因为另一个运算符“点”运算符(即 .)会自动引用或取消引用其左参数。因此,例如,如果我们具有以下定义:
    struct X { n: u32 };

    impl X {
    fn method(&self) -> u32 { self.n }
    }

    然后,尽管 method()通过引用引用了 self,但 self.n会自动取消引用它,因此您不必键入 (*self).n。调用 method()时也会发生类似的情况:
    let x = X { n: 12 };
    let n = x.method();

    在这里,编译器会自动在 x中引用 x.method(),因此您不必编写 (&x).method()

    最后一段代码也演示了特殊的 &self语法。在这个示例中,它的意思是 self: &Self,或更具体地说,是 self: &X&mut self*const self*mut self也可以使用。

    因此,引用是Rust中的主要指针类型,几乎应始终使用它。不受引用限制的原始指针应在实现高级抽象(集合,智能指针等)的低级代码和FFI(与C库进行交互)中使用。

    Rust也有 dynamically-sized (or unsized) types。这些类型没有确定的静态已知大小,因此只能通过指针/引用使用。但是,仅指针是不够的-需要其他信息,例如,切片的长度或用于特征对象的虚拟方法表的指针。此信息被“嵌入”到未定型类型的指针中,从而使这些指针“变胖”。

    胖指针基本上是一种结构,其中包含指向数据段的实际指针和一些其他信息(切片的长度,特征对象的vtable的指针)。这里重要的是Rust对用户绝对透明地处理了有关指针内容的这些细节-如果您传递 &[u32]*mut SomeTrait值,则将自动传递相应的内部信息。
    Box<T>是Rust标准库中的智能指针之一。它提供了一种在堆上分配足够的内存以存储相应类型的值的方法,然后用作句柄(指向该内存的指针)。 Box<T>拥有它所指向的数据;当删除它时,堆上的相应内存将被释放。

    思考盒子的一种非常有用的方法是将它们视为常规值,但具有固定的大小。也就是说, Box<T>等效于 T,只是它始终占用一定数量的字节,这些字节与您的计算机的指针大小相对应。我们说(拥有的)盒子提供了值(value)语义。在内部,它们使用原始指针来实现,就像几乎所有其他高级抽象一样。
    Box es(实际上,对于几乎所有其他智能指针,例如 Rc都是如此),也可以借用:您可以从 &T中获取 Box<T>。这可以使用 .运算符自动发生,也可以通过取消引用并再次引用来显式地实现:
    let x: Box<u32> = Box::new(12);
    let y: &u32 = &*x;

    在这方面, Box与内置指针相似-您可以使用解引用运算符来获取其内容。这是可能的,因为Rust中的解除引用运算符是可重载的,并且对于大多数(如果不是全部)智能指针类型都已重载。这样可以轻松借用这些指针的内容。

    最后, ref只是模式中的一种语法,用于获取引用类型的变量而不是值。例如:
    let x: u32 = 12;

    let y = x; // y: u32, a copy of x
    let ref z = x; // z: &u32, points to x
    let ref mut zz = x; // zz: &mut u32, points to x

    可以使用引用运算符重写以上示例:
    let z = &x;
    let zz = &mut x;

    (这也会使它更加惯用),例如在 ref必不可少的情况下,例如,将引用引入枚举变量中时:
    let x: Option<Vec<u32>> = ...;

    match x {
    Some(ref v) => ...
    None => ...
    }

    在上面的示例中, x仅在整个 match语句内借用,这允许在此 x之后使用 match。如果我们这样写:
    match x {
    Some(v) => ...
    None => ...
    }

    那么 x将被此 match占用,并且在此之后将无法使用。

    关于pointers - Box,ref和&和*之间的理解和关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65314147/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com