Lets say I want to write a type that builds a fairly large string (lets say of html) then returns it without copying or cloning the string. Is there a way that I can implement an unwrap
function that will prevent further access to the builder.
For example this works:
mod test {
use std::cell::RefCell;
struct StringBuilder {
buffer: RefCell<String>,
}
impl StringBuilder {
pub fn new() -> Self {
Self { buffer: RefCell::new(String::with_capacity(8000)) }
}
pub fn append(self: &Self, s: &str) -> &Self {
self.buffer.borrow_mut().push_str(s);
self
}
pub fn unwrap(self: &Self) -> String {
self.buffer.borrow().clone()
}
}
#[test]
pub fn test() {
let sb = StringBuilder::new();
sb.append("a").append("b");
let s = sb.unwrap();
println!("{s}");
}
}
But it has to clone the string in the unwrap
. I thought about making the unwrap
take &mut Self
instead of &Self
preventing any further references in the calling code, but the mutable reference goes out of scope right away.
4
I would do something like
pub fn build(self) -> String {
self.buffer.into_inner()
}
A value (not a reference) for self
consumes the builder.
I would also choose another name than unwrap
since in Rust it refers to Option
or Result
; build
seems appropriate for a builder.
See this documentation.
2
After some more experimenting, it looks like unwrap
should be written as
pub fn unwrap(self: Self) -> String {
self.buffer.take()
}
With this implementation unwrap
takes ownership of itself, and drops itself when the unwrap
function returns. The take
function of RefCell
does a similar thing, moving the contents out of the RefCell
and returning ownership to caller of unwrap