从像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()
返回读取的字节数)?为什么不使用元组?这仅仅是个人偏好的问题吗?
答案 0 :(得分:8)
如果read_to_string
想要返回拥有的String
,这意味着每次调用它时都必须堆分配一个新的String
。此外,由于Read
实现并不总是知道要读取多少数据,因此可能需要多次逐步重新分配正在进行的工作String
。这也意味着每个临时String
都必须返回到要销毁的分配器。
这很浪费。 Rust是一种系统编程语言。系统编程语言厌恶浪费。
相反,调用者负责分配和提供缓冲区。如果您只拨打read_to_string
一次,则不会发生任何变化。但是,如果将其称为 more 而不是一次,则可以多次重复使用相同的缓冲区,而无需使用常量分配/调整大小/解除分配周期。虽然它不适用于这种特定情况,但类似的接口可以设计为也支持堆栈缓冲区,这意味着在某些情况下您可以完全避免堆活动。
让调用者传入缓冲区比其他方法更灵活。