传递可变引用与创建和返回拥有值是否总是更可取?

时间:2017-08-18 12:24:32

标签: reference rust idiomatic

从像Python这样的动态语言转向Rust,我不习惯于编程模式,在这种编程模式中,您提供了一个函数,该函数具有对空数据结构的可变引用,并且该函数会填充它。一个典型的例子是将文件读入String

let mut f = File::open("file.txt").unwrap();
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();

对于我熟悉Python的眼睛,你只需在函数中创建一个自有值并将其作为返回值移出的API看起来更直观/符合人体工程学/你有什么:

let mut f = File::open("file.txt").unwrap();
let contents = f.read_to_string().unwrap();

由于Rust标准库采用了以前的道路,我认为必须有一个原因。

使用参考图案总是更好吗?如果是这样,为什么? (性能原因?具体是什么?)如果没有,我如何发现可能有益的情况?除了填充结果数据结构之外,当我想要返回另一个值时,它是否最有用(如上面的第一个例子,其中.read_to_string()返回读取的字节数)?为什么不使用元组?这仅仅是个人偏好的问题吗?

1 个答案:

答案 0 :(得分:8)

如果read_to_string想要返回拥有的String,这意味着每次调用它时都必须堆分配一个新的String。此外,由于Read实现并不总是知道要读取多少数据,因此可能需要多次逐步重新分配正在进行的工作String。这也意味着每个临时String都必须返回到要销毁的分配器。

这很浪费。 Rust是一种系统编程语言。系统编程语言厌恶浪费。

相反,调用者负责分配和提供缓冲区。如果您只拨打read_to_string一次,则不会发生任何变化。但是,如果将其称为 more 而不是一次,则可以多次重复使用相同的缓冲区,而无需使用常量分配/调整大小/解除分配周期。虽然它不适用于这种特定情况,但类似的接口可以设计为也支持堆栈缓冲区,这意味着在某些情况下您可以完全避免堆活动。

让调用者传入缓冲区比其他方法更灵活。