pri*_*ior 20 ownership rust borrowing
在编写函数时,如何决定是引用还是使用输入参数?
例如,我应该这样做吗?
fn foo(val: Bar) -> bool { check(val) } // version 1
Run Code Online (Sandbox Code Playgroud)
或者使用引用参数代替?
fn foo(val: &Bar) -> bool { check(*val) } // version 2
Run Code Online (Sandbox Code Playgroud)
在客户端,如果我只有第二个版本但想要消耗我的价值,我必须这样做:
// given in: Bar
let out = foo(&in); // using version 2 but wanting to consume ownership
drop(in);
Run Code Online (Sandbox Code Playgroud)
另一方面,如果我只有第一个版本但想保留我的参考,我必须这样做:
// given in: &Bar
let out = foo(in.clone()); // using version 1 but wanting to keep reference alive
Run Code Online (Sandbox Code Playgroud)
那么哪个是首选,为什么?
做出此选择时是否有任何性能考虑?或者编译器是否使它们在性能方面等效,以及如何实现?
您什么时候想提供两个版本(通过特征)?在那些时候,您如何编写这两个函数的底层实现——您是否复制每个方法签名中的逻辑,或者您是否有一个代理到另一个函数?哪个到哪个,为什么?
Sch*_*ern 21
Rust 的目标是拥有与 C/C++ 类似的性能和语法,而没有内存问题。为此,它避免了垃圾收集之类的事情,而是强制执行特定的严格的“所有权”和“借用”内存模型。这些是 Rust 中的关键概念。我建议阅读《The Rust Book》中的《理解所有权》。
\n内存所有权的规则是...
\n强制执行单一所有者可以避免 C 和 C++ 程序典型的许多错误和复杂性,同时避免运行时复杂且缓慢的内存管理。
\n仅此无法走得太远,因此 Rust 提供了参考。引用可以让函数安全地“借用”数据,而无需获取所有权。您可以拥有任意数量的不可变引用,也可以仅拥有一个可变引用。
\n当应用于函数调用时,传递值将所有权传递给函数。传递引用是“借用”,保留所有权。
\n了解所有权、借用以及随后的生命周期真的非常非常重要。但这里有一些经验法则。
\n请注意其中不包含的内容:性能。让编译器来处理这个问题。
\n假设check只读取数据并检查是否正常,则应该采用引用。所以你的例子是......
fn foo(val: &Bar) -> bool { check(val) }\nRun Code Online (Sandbox Code Playgroud)\n\n\n在客户端,如果我只有第二个版本但想要消耗我的价值......
\n
没有理由需要一个需要引用的函数来做到这一点。如果该函数的工作是管理内存,则将其所有权传递给它。如果不是,那么管理你的记忆就不是它的工作了。
\n也无需手动调用drop. 您只需让变量超出范围,它就会自动删除。
\n\n您什么时候想提供两个版本(通过特征)?
\n
你不会的。如果一个函数可以获取引用,那么它就没有理由获取所有权。
\n如果函数需要所有权,则应该按值传递。如果函数只需要引用,则应按引用传递。
fn foo(val: Bar)当函数不需要工作时按值传递可能需要用户克隆该值。在这种情况下,优选通过引用传递,因为可以避免克隆。
当函数需要所有权时通过引用传递fn foo(val: &Bar)将要求它复制或克隆该值。在这种情况下,按值传递是首选,因为它使用户可以控制是否转移或克隆现有值的所有权。该函数不必做出该决定,并且可以避免克隆。
有一些例外,简单的原语i32可以按值传递,而不会造成任何性能损失,并且可能更方便。
您什么时候想提供两个版本(通过特征)?
您可以使用该Borrow特征:
fn foo<B: Borrow<Bar>>(val: B) -> bool {
check(val.borrow())
}
let b: Bar = ...;
foo(&b); // both of
foo(b); // these work
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5038 次 |
| 最近记录: |