At the start of a program, it is straightforward to clone
data all over the
place to get things working, and, soon enough, the program is overrun by them.
Switching away from clones can be hard because it requires fighting with the
borrow checker, and alternative
solutions
aren't quite right for the job. How do you cut down allocations from cloning as
if you were borrowing without winding up in borrow hell? Consider using a Cow.
Cow
stands for Clone on Write and they are underrated for what
they can do in this regard. On their own cows are usually larger than their
owned or borrowed
variants,
but cutting down careless memory allocations may help improve performance.
Use a Cow
when there is data allocated outside of a function or block, and
there is some runtime logic that determines whether a write takes place. Cows
are a useful mechanism for transferring ownership lazily by cloning data once
and only once.
Cows are like hybrids such that at runtime, they might be borrowing data that's already been around, or they may be handing out borrows to an owned piece of data that they own.
Consider a function that replaces values in a string that we already have
allocated outside of the function. Replacing characters might mean changing the
size of the string or it could be a case of soft failure where we replace
invalid characters with the unicode replacement character
U+FFFD,
as is the case for
String::from_utf8_lossy
.
We should strive to recycle what values are already hanging around if we can
help it. We can recycle in other ways, such as taking a reference to a default
rather than assuming it must always be allocated on the fly, or having a
collection lazily clone and take ownership of values as it needs to rather than
cloning the collection from the start. With a bit of imagination, there are
several places that Cows can be used to improve performance and cut down on
clones.