为什么Rust中的默认行为是在赋值时执行移动,而不是创建另一个“移动”;参考资料;价值?

为什么Rust中的默认行为是在赋值时执行移动,而不是创建另一个“移动”;参考资料;价值?,rust,Rust,如果您执行以下操作,则会导致生锈: let v1 = String::from("hello"); let v2 = v1; println!("{}", v1); 您将得到一个编译器错误,因为Rust中的=执行移动,而不是复制或“共享” 我正在阅读,其中更详细地讨论了这一点: 但还有一个更大的问题,关于解除分配。如果使用共享语义,则v1和v2都将拥有单个数据缓冲区,因此当它们被释放时,相同的堆缓冲区将被释放两次。缓冲区不能分配两次,否则会导致内存损坏,从而导致程序故障。为了解决这个问题,使用

如果您执行以下操作,则会导致生锈:

let v1 = String::from("hello");
let v2 = v1;
println!("{}", v1);
您将得到一个编译器错误,因为Rust中的
=
执行移动,而不是复制或“共享”

我正在阅读,其中更详细地讨论了这一点:

但还有一个更大的问题,关于解除分配。如果使用共享语义,则
v1
v2
都将拥有单个数据缓冲区,因此当它们被释放时,相同的堆缓冲区将被释放两次。缓冲区不能分配两次,否则会导致内存损坏,从而导致程序故障。为了解决这个问题,使用共享语义的语言不会使用这种内存在变量作用域的末尾释放内存,而是采用垃圾收集

我的问题是,当
v1
v2
超出范围时,为什么需要释放两次数据缓冲区?除了“销毁”
v1
v2
,我们不能只释放一次数据缓冲区吗?我知道
v1
v2
实际上是值,而不是引用,但不让它们成为具有上述行为的“智能引用”的理由是什么

[…]不让它们成为“智能参考”的理由是什么

主要是表演。Rust是关于“零成本抽象”(一个由C++创造的术语)。如果程序员不需要该语言,则该语言不应产生运行时开销。此类“智能引用”将是引用计数指针(如Rust中的
Rc
Arc
,或C++中的
shared_ptr
),或者需要垃圾收集器。这两种解决方案都有这样的开销

[…]不让它们成为“智能参考”的理由是什么


主要是表演。Rust是关于“零成本抽象”(一个由C++创造的术语)。如果程序员不需要该语言,则该语言不应产生运行时开销。此类“智能引用”将是引用计数指针(如Rust中的
Rc
Arc
,或C++中的
shared_ptr
),或者需要垃圾收集器。这两种解决方案都有这样的开销。

您认为智能指针可以免费使用吗?这是有代价的,所以我们尽量避免它,但以一种安全的方式,所以生锈有很多规则,为什么会有移动。但是如果你愿意,你也可以在Rust中使用引用计数器。你可以通过让v2=&v1(无开销)自由创建引用。或者创建一个引用计数的引用(一些开销)。或者使用副本类型(字符串数据的一些开销)。Rust允许您选择所需内容(与Java等语言相反,Java几乎总是选择垃圾收集引用)。您认为智能指针可以自由使用吗?这是有代价的,所以我们尽量避免它,但以一种安全的方式,所以生锈有很多规则,为什么会有移动。但是如果你愿意,你也可以在Rust中使用引用计数器。你可以通过让v2=&v1(无开销)自由创建引用。或者创建一个引用计数的引用(一些开销)。或者使用副本类型(字符串数据的一些开销)。Rust允许您选择所需内容(与Java等语言相反,Java几乎总是选择垃圾收集引用)。感谢您的回复!是的,我想当你不是真的在努力完成最后几个周期的性能时,很容易接受这样的智能引用…哦,对不起,我不确定我怎么会错过。不,这里更详细的内容显然超出了范围。谢谢您的回复!是的,我想当你不是真的在努力完成最后几个周期的性能时,很容易接受这样的智能引用…哦,对不起,我不确定我怎么会错过。不,这里更详细的讨论似乎超出了范围。