gpt4 book ai didi

rust - ToString 和 IntoString 的区别

转载 作者:行者123 更新时间:2023-11-29 07:43:26 27 4
gpt4 key购买 nike

我想知道两者之间有什么区别:

"some string".to_string()


"some string".into_string()

前者好像来自 ToString ,这是很清楚的。

然而,后者似乎来自 IntoString ,这对我来说不太清楚。
consume是什么意思一个值 ?这两个特质有什么区别?

进行一些挖掘后的其他信息。

这是 the current implementation of into_string 对于 String .如您所见,它只返回自身,因此没有进行分配。

最佳答案

移动语义

What does it mean to consume a value?



消费一个值与移动一个值有关。在讨论这两个特征之间的差异之前,我将举一些例子来说明移动值的含义。让我们创建一个 Vec Ascii 字符: asciis .
fn main() {
let asciis = vec!['h'.to_ascii(), 'i'.to_ascii()];
println!("{}", asciis);
}

Internally , Vec是一个包含三个字段的结构体:
  • Vec的长度.
  • Vec容量.
  • 指向 Vec 管理的数据的指针.

  • 从图形上看, Vec 的内存布局它管理的数据可能看起来像这样。
    Stack: asciis           Heap: 
    +----------+ +----------+
    0xF0 | data | ----> 0xA0 | 'h' |
    +----------+ +----------+
    0xF4 | length | 0xA1 | 'i' |
    +----------+ +----------+
    0xF8 | capacity |
    +----------+

    当我们的 Vec超出范围,它释放它管理的内存。释放的内存对我们来说是垃圾。访问释放的内存是错误的。这将类似于以下内容。 Vec消失了,堆上的内存已被释放。
                            Heap: 
    +----------+
    0xA0 | GARBAGE |
    +----------+
    0xA1 | GARBAGE |
    +----------+

    现在,让我们回到我们的代码并尝试复制 asciis .
    fn main() {
    let asciis = vec!['h'.to_ascii(), 'i'.to_ascii()];
    {
    let an_attempted_copy = asciis;
    }
    println!("{}", asciis);
    }

    让我们猜一下 an_attempted_copyasciis 的副本.在我们复制之后,我们的内存可能看起来像下面这样。
    Stack: asciis           Heap:                   Stack: an_attempted_copy
    +----------+ +----------+ +----------+
    0xF0 | data | ----> 0xA0 | 'h' | <---- 0xE0 | data |
    +----------+ +----------+ +----------+
    0xF4 | length | 0xA1 | 'i' | | length |
    +----------+ +----------+ +----------+
    0xF8 | capacity | | capacity |
    +----------+ +----------+

    就在我们尝试之前 println! asciis , an_attempted_copy超出范围!和之前一样,我们 Vec指向的数据被释放。
    Stack: asciis           Heap:                   
    +----------+ +----------+
    0xF0 | data | ----> 0xA0 | GARBAGE |
    +----------+ +----------+
    0xF4 | length | 0xA1 | GARBAGE |
    +----------+ +----------+
    0xF8 | capacity |
    +----------+

    哦哦, asciis指向释放的内存!这是个坏消息,因为我们即将 println! asciis .

    那么我们该如何补救呢?嗯,这里有两个选择。
  • 当我们复制asciis进入 an_attempted_copy ,我们可以复制asciis指向的数据到一块新分配的内存中。其他语言如 C++ 这样做。
  • 而不是复制 asciis ,我们可以移动它!这就是 rust 的作用。

  • 那么搬家是什么意思呢?这意味着 an_attempted_copy将获得以前由 asciis 指向的数据的所有权. asciis失去所有权,我们不能再使用它。让我们重命名 an_attempted_copy为了清楚起见。
    fn main() {
    let asciis = vec!['h'.to_ascii(), 'i'.to_ascii()];
    {
    let actually_a_move = asciis;
    }
    println!("{}", asciis);
    }

    现在,让我们在进入 actually_a_move 后立即绘制我们的内存布局。 .
    Stack: asciis           Heap:                   Stack: actually_a_move
    +----------+ +----------+ +----------+
    0xF0 | GARBAGE | 0xA0 | 'h' | <---- 0xE0 | data |
    +----------+ +----------+ +----------+
    0xF4 | GARBAGE | 0xA1 | 'i' | | length |
    +----------+ +----------+ +----------+
    0xF8 | GARBAGE | | capacity |
    +----------+ +----------+
    asciis不再拥有内存,所以我们不能使用 asciis了。这意味着它几乎是垃圾。所以如果我们不能使用 asciis不再,当我们 println! 会发生什么它?我们得到以下错误。
    <anon>:6:24: 6:30 error: use of moved value: `asciis`
    <anon>:6 println!("{}", asciis);
    ^~~~~~
    note: in expansion of format_args!
    <std macros>:2:23: 2:77 note: expansion site
    <std macros>:1:1: 3:2 note: in expansion of println!
    <anon>:6:9: 6:32 note: expansion site
    <anon>:4:17: 4:32 note: `asciis` moved here because it has type `collections::vec::Vec<std::ascii::Ascii>`, which is moved by default (use `ref` to override)
    <anon>:4 let actually_a_move = asciis;
    ^~~~~~~~~~~~~~~
    error: aborting due to previous error

    正如预期的那样,rust 编译器告诉我们我们正在尝试使用 ascii ,但是 ascii是一个移动的值;这是错误的。

    移动语义(以及相关主题,如借用和生命周期)是困难的事情。我只是在这里触及了表面。更多信息, rust by examplethis stackoverflow问题都是很好的资源。
    to_string对比 into_string

    What is the difference between the two traits?



    现在我已经探索了消耗或移动值的概念,让我们来看看这两个特征之间的差异。我们先来看 to_string的类型签名.
    fn to_string(&self) -> String;

    该函数引用了 self并返回一个新的 String供我们使用。我还没有讨论引用资料以及它们如何影响运动,但是当我说这里没有进行任何运动时请相信我。

    现在让我们看看 into_string 的类型签名.
    fn into_string(self) -> String;

    此函数不引用 self .相反, self被移动到函数中。

    那么这种差异的含义是什么?让我们看一个例子。
    fn main() {
    let asciis = vec!['h'.to_ascii(), 'i'.to_ascii()];
    let no_moves_here = asciis.to_string();
    println!("{}", asciis);
    }

    我们再次创建一个 VecAscii人物。然后,当我们拨打 asciis.to_string() ,全新 String已创建并 asciis从不移动。此代码将按照您的预期构建和运行,打印出 [h, i] .现在,让我们使用 into_string .
    fn main() {
    let asciis = vec!['h'.to_ascii(), 'i'.to_ascii()];
    let uh_oh_we_just_moved_asciis = asciis.into_string();
    println!("{}", asciis);
    }

    这是我们在尝试构建此代码时收到的错误消息。
    <anon>:4:24: 4:30 error: use of moved value: `asciis`
    <anon>:4 println!("{}", asciis);
    ^~~~~~
    note: in expansion of format_args!
    <std macros>:2:23: 2:77 note: expansion site
    <std macros>:1:1: 3:2 note: in expansion of println!
    <anon>:4:9: 4:32 note: expansion site
    <anon>:3:42: 3:48 note: `asciis` moved here because it has type `collections::vec::Vec<std::ascii::Ascii>`, which is non-copyable (perhaps you meant to use clone()?)
    <anon>:3 let uh_oh_we_just_moved_asciis = asciis.into_string();
    ^~~~~~
    error: aborting due to previous error

    所以发生了什么事?嗯 asciis正在移入函数 into_string .就像我们上次尝试使用 asciis 一样在我们移动它之后,rust 编译器将拒绝我们的代码。

    关于rust - ToString 和 IntoString 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25316115/

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