1
0
Fork 0
blog/content/decks/rust-lifetimes.html
Champlin, Saji 3df4f2a63f
Some checks failed
Build Blog / Build (push) Failing after 8m40s
add rust lifetimes presentation
2025-05-06 10:34:49 -05:00

143 lines
3.7 KiB
HTML

<section>
<h2> Lifetimes in Rust </h2>
<p> It was always there, but now it's explicit </p>
</section>
<section>
<h3>Recap: References </h3>
<ul>
<li><code>&MyStruct</code> is a reference/borrow of a struct</li>
<li class="fragment">If the underlying struct is <em>removed</em>, the reference is invalid </li>
<li class="fragment">In C++, it is entirely on you to manage this</li>
<li class="fragment"pre>Rust just makes this management explicit </li>
</ul>
</section>
<section>
<h3>Motivation</h3>
<pre ><code class="rust" data-trim data-line-numbers>
let x;
{
let y = 5;
x = &y;
} // uh oh
println!("x: {}", x); // hmmm
</code></pre>
<p>Rust will not compile this code</p>
</section>
<section>
<h3>Lifetimes</h3>
<ul>
<li> These always exist. </li>
<li class="fragment"> Sometimes the compiler needs some hints </li>
<li class="fragment"> We can <em>annotate</em> lifetimes to add hints </li>
</ul>
</section>
<section>
<h3>Annotation Example</h3>
<pre><code class="rust" data-trim data-line-numbers="1-10|12-23"><script type="text/template">
// 'a is a generic lifetime parameter. the borrow checker
// will infer which lifetime it represents and ensure
// that the relationships are valid.
fn longer_string<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("longer");
let result;
{
let string2 = String::from("short");
result = longest(&string1, &string2);
println("Longest: {}", result);
}
// can't do this. why?
// println("Longest: {}", result);
}
</script></code></pre>
<p class="fragment">The borrow checker will use the shortest lifetime</p>
</section>
<section>
<h3>Struct Example</h3>
<pre><code class="rust" data-trim data-line-numbers="1-5|7-12"><script type="text/template">
// again, 'a is a generic lifetime parameter.
struct Keyword<'a> {
word: &'a str,
parent: &'a str,
}
fn main() {
let example = String::from("This is the demo text");
let demo = example.get(12..16);
let kw = Keyword { word: demo, parent: example };
// kw cannot outlive demo or example
}
</script></code></pre>
</section>
<section>
<section>
<h3>Challenge: Circular references</h3>
<pre><code class="rust" data-trim data-line-numbers><script type="text/template">
struct Node<'a> {
data: u32,
next: Option<&'a Node<'a>>, // what does this mean?
}
let mut x = Node {value: 42, next: None };
let y = Node { value: 7, next: Some(&x) };
// and this is where we perish.
x.next = Some(&y);
</script></code></pre>
</section>
<section>
<h3>Rc + Refcell</h3>
<pre><code class="rust" data-trim data-line-numbers><script type="text/template">
use std::cell::RefCell;
use std::rc::Rc;
struct Node {
data: u32,
next: Option<Rc<RefCell<Node>>>,
}
</script></code></pre>
<ul>
<li> + safety of ownership/mutability at runtime</li>
<li> - there is a performance penalty</li>
<li> - a bit awkward to use.</li>
</ul>
</section>
<section>
<h3>Vec + Index</h3>
<pre><code class="rust" data-trim data-line-numbers><script type="text/template">
struct Graph {
nodes: Vec<Option<Node>>
}
struct Node {
data: u32,
next: usize, // index into graph.
}
</script></code></pre>
<ul>
<li> + fast, no weird Rc stuff</li>
<li> - bug prone, self managed, can dangle </li>
</ul>
</section>
<section>
<h3>3rd party libraries</h3>
<p><a href="https://github.com/orlp/slotmap/blob/master/examples/doubly_linked_list.rs">slotmap</a>: Like a hashmap, but with unique keys</p>
<p><a href="https://docs.rs/typed-arena/latest/typed_arena/#safe-cycles">typed-arena</a>: Arena allocator. Can only drop the whole arena</p>
</section>
</section>