In some ways, yes. There is little doubt that lifetimes have a maintenance cost associated with them.
There are techniques I use to eliminate them in some places:
Abstracting over lifetimes with generics
Here’s something I occasionally do for types with public fields that represent a file format, so that both deserialization is simple and serialization can be done with whatever is at hand:
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Poscar<
Comment = String,
Coord = Coords,
Elements = Vec<Element>,
pub comment: Comment,
pub coords: Coord,
pub elements: Elements,
impl<Comment, Coord, Elements> Poscar<Comment, Coord, Elements>
// ... methods ...
Poscar can be written without any explicit parameters, and it will refer to the type where all fields own their data (which is what is most commonly returned from a function). But somebody can also construct one with e.g. a
comment if they need to, and these cases are generally not inconvenient since oftentimes the type doesn’t need to be written.
Refcounting in high-level code
I used to deal with owned vs borrowed types throughout my entire base, but this gets very onerous in high-level application code that needs to be revised frequently.
When writing code that sits at the top of the food chain, don’t be afraid to use
Rc<[T]> as your “standard” string and vector types (once they no longer need to be mutated, of course). It will save you a lot of headache when refactoring.
'static can be used
Yesterday I was writing something that needs an RAII guard. The standard library’s MutexGuard borrows from its Mutex, but as long as that Mutex is static, then safe mutation is impossible (so aliasing is not a concern) and the guard can be given the
/// Guarantees that only one instance of Lammps may exist on a process,
/// if constructed through safe APIs.
pub static ref INSTANCE_LOCK: Mutex<InstanceLock> = Mutex::new(InstanceLock(()));
/// Proof that no instance of Lammps currently exists within the current process.
pub struct InstanceLock(());
/// A Lammps is built directly with the MutexGuard wrapper (rather than a reference)
/// to dodge an extra lifetime parameter.
pub type InstanceLockGuard = MutexGuard<'static, InstanceLock>;