Reputation: 107
This is my first bit of Rust code. I added the lifetime parameters to the inner function only because the compiler told me to. Although I understand the lifetime explanation in the Rust book, I couldn't have written this signature by myself.
fn transform_the_expression() {
fn create_formula<'t>(formula: & mut HashMap<& str, &'t str>, input: &'t str, re: Regex)->std::borrow::Cow<'t, str>{
let replacement = re.find(input).unwrap();
formula.insert("1", replacement.as_str());
let rest = re.replace(input, "1");
return rest;
}
let input = "(a+(b*c))";
use regex::Regex;
let re = Regex::new(r"\([\w\d][/*+-^][\w\d]\)").unwrap();
use std::collections::HashMap;
let mut formula = HashMap::new();
let result = create_formula(&mut formula, input, re);
println!("result = {:?}", result);
}
Upvotes: 0
Views: 126
Reputation: 14051
The compiler's great at telling you when you need to specify lifetimes, but not necessarily so good at letting you know which ones.
First of all, it's worth mentioning that there are lifetimes on every reference; it's just that there are lifetime elision rules which say how the compiler will fill them in if you don't specify them.
Back to your signature:
fn create_formula(formula: & mut HashMap<& str, &str>, input: &str, re: Regex)->std::borrow::Cow<_, str>
The first lifetime definitely needed is the one in Cow<_, str>
; you need to have a lifetime to put into there to declare the function. There are two choices: declare one, or use 'static
. In this case, the Cow
may point at part of the input
parameter, so you need to tie them together. First the new lifetime needs declaring by adding <'t>
(any name would do) after the function name, and then using it for input
and the return type:
fn create_formula<'t>(formula: & mut HashMap<& str, &str>, input: &'t str, re: Regex)->std::borrow::Cow<'t, str>
And finally you're putting borrowed parts of input
into the HashMap
. If the input
lifetime (which we've now named 't
) isn't tied to the HashMap
value, someone could pass in a hash map which lives longer than the input, leading to dangling pointers in the map. So we need to constrain it too, giving the final version:
fn create_formula<'t>(formula: & mut HashMap<&str, &'t str>, input: &'t str, re: Regex)->std::borrow::Cow<'t, str>
The key thing is that function signatures need to convince the compiler that all the uses of references are safe, and that often means you have to be explicit about the relationships between different reference parameters (and lifetime-parametric types) when the default (via the elision rules) don't say the right thing.
Upvotes: 4