Why would you use the same lifetimes for references in a structure?

This question is similar to When is it useful to define several lifetimes in a structure? but hopefully will be quite different. The answer to this question is useful, but it focuses on the advantages of one approach (using different lifetimes for links in the structure), but not on the disadvantages (if any). This question, therefore, seeks guidance on the choice of life time when creating structures.

Name this related version, since x and y must have the same lifetime:

struct Foo<'a> { x: &'a i32, y: &'a i32, } 

and name this free version, because the lifetime may vary:

 struct Foo<'a, 'b> { x: &'a i32, y: &'b i32, } 

The answer to the above question gives a clear case when the client code can be compiled / launched taking into account the free version, but will not be linked for the associated version. Isn't that the case when any client code that works for the linked version will also work for the free version and be guaranteed to be safe (i.e. Safe)? Obverse is not true. The free version is clearly more flexible from the point of view of the designer. Given that this is a good / accepted answer, the manual may be - when using links in a structure, they always give them different lifespan.

What is the disadvantage of this advice, ignoring additional typing? For example, is it ever useful to use the required links in a structure that have the same lifetime?

+7
struct rust lifetime
source share
1 answer

Is it always useful for links in the structure to have the same lifetime

Yes, and he goes beyond the framework. If the times of life were always different from each other, you could not write this function:

 fn foo<'a, 'b>(a: &'a str, b: &'b str) -> &str { // What lifetime to return? if (global_random_number() == 42) { a } else { b } } 

When applied to a structure, you can have something like this:

 struct EvenOrOdd<'a, 'b> { even: &'a str, odd: &'b str, } impl<'a, 'b> EvenOrOdd<'a, 'b> { fn do_it(&self, i: u8) -> &str { if i % 2 == 0 { self.even } else { self.odd } } } 

Note that while this compiler does not return a string that the structure itself can survive, and not what was intended. This code does not work, although it should work:

 fn foo<'a, 'b>(a: &'a str, b: &'b str) { let result = { EvenOrOdd { even: a, odd: b }.do_it(42) }; println!("{}", result); } 

This will work with standardized lifetimes:

 struct EvenOrOdd<'a> { even: &'a str, odd: &'a str, } impl<'a> EvenOrOdd<'a> { fn do_it(&self, i: u8) -> &'a str { if i % 2 == 0 { self.even } else { self.odd } } } 

This is the opposite of a related answer that contains a comment:

you want to be able to summarize the value and separate its parts after use

In this case, we want to take the aggregated value and combine them.

In more rare cases, you may need to cut a needle between different and standardized life spans:

 struct EvenOrOdd<'a, 'b: 'a> { even: &'a str, odd: &'b str, } impl<'a, 'b> EvenOrOdd<'a, 'b> { fn do_it(&self, i: u8) -> &'a str { if i % 2 == 0 { self.even } else { self.odd } } } 

Although this is useful when necessary, I cannot imagine crying and gnashing of teeth that could erupt if we had to write this every time.


ignore extra entry

I would not. Having

 foo<'a>(Bar<'a>) 

definitely better than

 foo<'a, 'b', 'c, 'd>(Bar<'a, 'b', 'c, 'd>) 

If you do not use additional generic parameters.

+5
source share

All Articles