Reputation: 2663
I am working on a random text generator which is going to store a "pattern" for output (among other parameters), and I think &str
is the right data type given that the user of my library will specify the pattern in his code. I'm using a "Builder" pattern to build a "Generator" struct, and I want to specify that the pattern will outlive both the builder and generator. Here's my code without lifetime parameters:
pub struct Generator {
pub pattern: &str,
}
impl Generator {
pub fn builder() -> GeneratorBuilder {
GeneratorBuilder::new()
}
}
pub struct GeneratorBuilder {
pattern: &str,
}
impl GeneratorBuilder {
pub fn new() -> Self {
Self {
pattern: "",
}
}
pub fn with_pattern(mut self, pattern: &str) -> Self {
self.pattern = pattern;
self
}
pub fn build(&self) -> Generator {
Generator {
pattern: self.pattern,
}
}
}
The compiler at this point tells me I need lifetime specifiers in both struct definitions, and if I follow its recommendations I end up with 'a
and '_
and 'static
at various places throughout my code. But this will not compile. The code now is:
pub struct Generator<'a> {
pub pattern: &'a str,
}
impl Generator<'_> {
pub fn builder() -> GeneratorBuilder<'static> {
GeneratorBuilder::new()
}
}
pub struct GeneratorBuilder<'a> {
pattern: &'a str,
}
impl GeneratorBuilder<'_> {
pub fn new() -> Self {
Self {
pattern: "",
}
}
pub fn with_pattern(mut self, pattern: &str) -> Self {
self.pattern = pattern;
self
}
pub fn build(&self) -> Generator {
Generator {
pattern: self.pattern,
}
}
}
The error I end up with is "lifetime may not live long enough" in the definition of function with_pattern
because "assignment requires that [pattern] must outlife [self]". My question is: Where do I need lifetime specifiers, and which ones do I need, to tell Rust that the str called "pattern" will live longer than the Generator and the GeneratorBuilder?
Upvotes: 1
Views: 229
Reputation: 23359
You need to be more detailed on which lifetimes are used at each stage. In particular you need to:
Generators
created with the default pattern have a 'static
lifetime. This is done by having new
return GeneratorBuilder<'static>
Generator
in GeneratorBuilder::build
. There are two possibles, either the lifetime of the &'_ self
reference or the lifetime embedded in the GeneratorBuilder<'_>
. By default the compiler takes the lifetime of the reference but you want the other one: fn build<'b>(&'b self) -> Generator<'a>
(the 'b
lifetime can actually be omitted here, I've just added it to make the distinction more explicit).Complete working example:
#[derive (Debug)]
pub struct Generator<'a> {
pub pattern: &'a str,
}
impl<'a> Generator<'a> {
pub fn builder() -> GeneratorBuilder<'a> {
GeneratorBuilder::new()
}
}
pub struct GeneratorBuilder<'a> {
pattern: &'a str,
}
impl<'a> GeneratorBuilder<'a> {
pub fn new() -> GeneratorBuilder<'static> {
GeneratorBuilder {
pattern: "default",
}
}
pub fn with_pattern(mut self, pattern: &'a str) -> Self {
self.pattern = pattern;
self
}
pub fn build(&self) -> Generator<'a> {
Generator {
pattern: self.pattern,
}
}
}
fn main() {
let g = GeneratorBuilder::new().build();
println!("{g:?}");
let g = GeneratorBuilder::new().with_pattern ("foobar").build();
println!("{g:?}");
}
Upvotes: 2
Reputation: 15074
What you need to do is just use 'a
everywhere:
pub struct Generator<'a> {
pub pattern: &'a str,
}
impl<'a> Generator<'a> {
pub fn builder() -> GeneratorBuilder<'a> {
GeneratorBuilder::new()
}
}
pub struct GeneratorBuilder<'a> {
pattern: &'a str,
}
impl<'a> GeneratorBuilder<'a> {
pub fn new() -> Self {
Self {
pattern: "",
}
}
pub fn with_pattern(mut self, pattern: &'a str) -> Self {
self.pattern = pattern;
self
}
pub fn build(&self) -> Generator {
Generator {
pattern: self.pattern,
}
}
}
Upvotes: 1