Box, ref, & 之间的理解和关系和 * [英] Understanding and relationship between Box, ref, & and *

查看:13
本文介绍了Box, ref, & 之间的理解和关系和 *的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm a bit confused about how pointers work in Rust. There's ref, Box, &, *, and I'm not sure how they work together.

以下是我目前的理解:

  1. Box 并不是真正的指针 - 它是一种在堆上分配数据并在函数参数中传递无大小类型(尤其是特征)的方法.
  2. ref 用于模式匹配以借用您匹配的内容,而不是获取它.例如,

  1. Box isn't really a pointer - it's a way to allocate data on the heap, and pass around unsized types (traits especially) in function arguments.
  2. ref is used in pattern matching to borrow something that you match on, instead of taking it. For example,

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) 来传递我想要保留所有权的数据.

  • & is used to make a borrow (borrowed pointer). If I have a function fn foo(&self) then I'm taking a reference to myself that will expire after the function terminates, leaving the caller's data alone. I can also pass data that I want to retain ownership of by doing bar(&mydata).

    谁能给我解释第四种类型的指针,并验证我对其他类型的理解是否正确?我也很感激有人指出我没有提到的任何常见用例.

    Could someone explain the 4th type of pointer to me, and verify that my understanding of the other types is correct? I'd also appreciate anyone pointing out any common use cases that I haven't mentioned.

    推荐答案

    首先,您列出的所有项目实际上都是不同的东西,即使它们与指针有关.Box 是库定义的智能指针类型;ref 是模式匹配的语法;& 是一个引用操作符,在引用类型中兼作符号;* 是一个解引用操作符,在原始指针类型中作为一个符号加倍.更多解释见下文.

    First of all, all of the items you listed are really different things, even if they are related to pointers. Box is a library-defined smart pointer type; ref is a syntax for pattern matching; & is a reference operator, doubling as a sigil in reference types; * is a dereference operator, doubling as a sigil in raw pointer types. See below for more explanation.

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

    There are four basic pointer types in Rust which can be divided in two groups - references and raw pointers:

    &T        - immutable (shared) reference
    &mut T    - mutable (exclusive) reference
    
    *const T  - immutable raw pointer
    *mut T    - mutable raw pointer
    

    最后两个之间的区别非常小,因为可以不受任何限制地转换为另一个,因此 const/mut 区别主要用作 lint.可以自由地创建指向任何对象的原始指针,例如,它们也可以从整数中凭空创建.

    The difference between the last two is very thin, because either can be cast to another without any restrictions, so const/mut distinction there serves mostly as a lint. Raw pointers can be created freely to anything, and they also can be created out of thin air from integers, for example.

    当然,引用并非如此——引用类型及其交互定义了 Rust 的一个关键特性:借用.引用对如何创建、何时创建、如何使用以及如何相互交互有很多限制.作为回报,它们可以在没有 unsafe 块的情况下使用.不过,借用究竟是什么以及它的工作原理超出了本答案的范围.

    Naturally, this is not so for references - reference types and their interaction define one of the key feature of Rust: borrowing. References have a lot of restrictions on how and when they could be created, how they could be used and how they interact with each other. In return, they can be used without unsafe blocks. What borrowing is exactly and how it works is out of scope of this answer, though.

    引用和原始指针都可以使用 & 操作符来创建:

    Both references and raw pointers can be created using & operator:

    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 块:

    Both references and raw pointers can be dereferenced using * operator, though for raw pointers it requires an unsafe block:

    *ref1; *ref2;
    
    unsafe { *raw1; *raw2; }
    

    解引用运算符经常被省略,因为另一个运算符点"运算符(即 .)会自动引用或解引用其左参数.因此,例如,如果我们有这些定义:

    The dereference operator is often omitted, because another operator, the "dot" operator (i.e., .), automatically references or dereferences its left argument. So, for example, if we have these definitions:

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

    然后,尽管 method() 通过引用获取 selfself.n 会自动取消引用它,因此您不必输入 (*self).n.类似的事情发生在 method() 被调用时:

    then, despite that method() takes self by reference, self.n automatically dereferences it, so you won't have to type (*self).n. Similar thing happens when method() is called:

    let x = X { n: 12 };
    let n = x.method();
    

    这里,编译器自动引用 x.method() 中的 x,所以你不必写 (&x).method().

    Here, the compiler automatically references x in x.method(), so you won't have to write (&x).method().

    最后一段代码也演示了特殊的 &self 语法.在本例中,它仅表示 self: &Self,或者更具体地说,是 self: &X.&mut self*const self*mut self 也可以.

    The next to last piece of code also demonstrated the special &self syntax. It means just self: &Self, or, more specifically, self: &X in this example. &mut self, *const self, *mut self also work.

    因此,引用是 Rust 中的主要指针类型,几乎应该总是使用.没有引用限制的原始指针应该用于实现高级抽象(集合、智能指针等)的低级代码和 FFI(与 C 库交互).

    So, references are the main pointer kind in Rust and should be used almost always. Raw pointers, which don't have restrictions of references, should be used in low-level code implementing high-level abstractions (collections, smart pointers, etc.) and in FFI (interacting with C libraries).

    Rust 也有动态大小(或非大小)类型.这些类型没有明确的静态已知大小,因此只能通过指针/引用使用.然而,只有一个指针是不够的 - 需要额外的信息,例如,切片的长度或指向 trait 对象的虚拟方法表的指针.此信息嵌入"在指向未确定大小的类型的指针中,使这些指针变得胖".

    Rust also has dynamically-sized (or unsized) types. These types do not have a definite statically-known size and therefore can only be used through a pointer/reference. However, only a pointer is not enough - additional information is needed, for example, length for slices or a pointer to a virtual methods table for trait objects. This information is "embedded" in pointers to unsized types, making these pointers "fat".

    胖指针基本上是一个结构,它包含指向数据块的实际指针和一些附加信息(切片的长度,特征对象的 vtable 指针).这里重要的是 Rust 处理这些关于指针内容的细节对用户绝对透明 - 如果你传递 &[u32]*mut SomeTrait 值,相应的内部信息将自动传递.

    A fat pointer is basically a structure which contains the actual pointer to the piece of data and some additional information (length for slices, pointer to vtable for trait objects). What's important here is that Rust handles these details about pointer contents absolutely transparently for the user - if you pass &[u32] or *mut SomeTrait values around, corresponding internal information will be automatically passed along.

    Box 是 Rust 标准库中的智能指针之一.它提供了一种在堆上分配足够内存以存储相应类型的值的方法,然后它充当句柄,指向该内存的指针.Box 拥有它指向的数据;当它被删除时,堆上相应的一块内存被释放.

    Box<T> is one of the smart pointers in the Rust standard library. It provides a way to allocate enough memory on the heap to store a value of the corresponding type, and then it serves as a handle, a pointer to that memory. Box<T> owns the data it points to; when it is dropped, the corresponding piece of memory on the heap is deallocated.

    考虑框的一种非常有用的方法是将它们视为常规值,但具有固定大小.也就是说,BoxT 等价,除了它总是占用与机器指针大小相对应的字节数.我们说(拥有的)盒子提供了值语义.在内部,它们使用原始指针实现,就像几乎所有其他高级抽象一样.

    A very useful way to think of boxes is to consider them as regular values, but with a fixed size. That is, Box<T> is equivalent to just T, except it always takes a number of bytes which correspond to the pointer size of your machine. We say that (owned) boxes provide value semantics. Internally, they are implemented using raw pointers, like almost any other high-level abstraction.

    Boxes(事实上,几乎所有其他智能指针都是如此,比如Rc)也可以借用:你可以得到一个&TBox.这可以使用 . 运算符自动发生,或者您可以通过取消引用并再次引用它来显式实现:

    Boxes (in fact, this is true for almost all of the other smart pointers, like Rc) can also be borrowed: you can get a &T out of Box<T>. This can happen automatically with the . operator or you can do it explicitly by dereferencing and referencing it again:

    let x: Box<u32> = Box::new(12);
    let y: &u32 = &*x;
    

    在这方面,Boxes 类似于内置指针 - 您可以使用解引用运算符来访问它们的内容.这是可能的,因为 Rust 中的解引用运算符是可重载的,并且对于大多数(如果不是全部)智能指针类型,它都会被重载.这允许轻松借用这些指针内容.

    In this regard, Boxes are similar to built-in pointers - you can use dereference operator to reach their contents. This is possible because the dereference operator in Rust is overloadable, and it is overloaded for most (if not all) of the smart pointer types. This allows easy borrowing of these pointers contents.

    最后,ref 只是模式中的一种语法,用于获取引用类型的变量而不是值.例如:

    And, finally, ref is just a syntax in patterns to obtain a variable of the reference type instead of a value. For example:

    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
    

    虽然上面的例子可以用引用运算符重写:

    While the above example can be rewritten with reference operators:

    let z = &x;
    let zz = &mut x;
    

    (这也会使它更惯用),在某些情况下 ref 是必不可少的,例如,当将引用引入枚举变体时:

    (which would also make it more idiomatic), there are cases when refs are indispensable, for example, when taking references into enum variants:

    let x: Option<Vec<u32>> = ...;
    
    match x {
        Some(ref v) => ...
        None => ...
    }
    

    在上面的例子中,x 只在整个match 语句中被借用,它允许在这个match<之后使用x/代码>.如果我们这样写:

    In the above example, x is only borrowed inside the whole match statement, which allows using x after this match. If we write it as such:

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

    然后 x 将被这个 match 消耗,并且在它之后将变得不可用.

    then x will be consumed by this match and will become unusable after it.

    这篇关于Box, ref, &amp; 之间的理解和关系和 *的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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