Recently, while I was working on my CityDB personal project, I ran into a few cases where I’d like to improve performance by not cloning anywhere. As such, I started diving deeper into the realm of lifetimes and variance and decided to chart out my learnings here.

Jon Gjengset did an indepth stream about lifetimes and did a deep dive on StrSplit, a C Library that takes a string and a delimeter and splits the passed in string at the first occurrence. StrSplit also mutates the input in the process, which also turns out to be especially important.

The port of the code that I wrote up while going through his stream can be found in my rust-playground repo. The rest of this post will go over the issues that were discussed and how variance played a big role at guranteeing safety.

What is a lifetime?

Defining Lifetimes

Generic Lifetimes

struct StrSplit<'a> {
    remainder: &'a str,
    delimeter: &'a str
}

impl<'a> StrSplit<'a> {
    ...
}

<’_> Lifetime

Variance

I’ll be making a future post on variance going over yet another port of a C library but briefly variance consists of the following types:

  • Covariance
  • CounterVariance
  • Invariance

The Rustonomican does a fantastic job going over the definitions and I highly recommend reviewing that.

A brief summary of this can be found here: Variance table screenshot

Multiple Lifetimes!

struct StrSplit<'a, 'b> {
    remainder: &'a str,
    delimeter: &'b str
}

impl<'a, 'b> StrSplit<'a, 'b> {
    ...
}