I tried to reason about the implications of the two approaches, but I have a gut feeling that in this case, since we're creating a new instance of Measurement, it shouldn't really make any difference if the data_source argument's lifetime is tied to the 'ds lifetime of the impl block or not, since we're in both cases "bringing into existence" something new that will be tied to the lifetime of such data_source argument.
In other words, there's no pre-existing instance of Measurements whose lifetime might impose different restrictions / conditions.
But I don't know if this is a correct line-of-thought and I would like in any case to be able to talk about this with more strict / precise terminology.
More generally, I always struggle to visualize what the 'a in impl<'a> SomeStruct<'a> implies when relating to method / associated functions arguments' lifetimes, so any help in that department would also be greatly appreciated...
At least for generic type parameters, this method can result in needing extra annotations. Lifetimes are a bit better at being inferred, but they might run into the same kind of issue:
error[E0282]: type annotations needed
--> src/main.rs:12:13
|
12 | let _ = Newtype::new(42u32);
| ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Newtype`
|
help: consider specifying the generic argument
|
12 | let _ = Newtype::<T>::new(42u32);
| +++++
Oh, my bad!
I wasn't able to find this while searching for similar questions.
That pretty much answers my doubts, I now have a cleaner idea and, inspired by the playground mentioned in this comment I wrote down a snippet to summarise more or less everything:
struct Foo<'a> {
data: &'a str,
}
impl<'a> Foo<'a> {
/***** CONSTRUCTORS WITH ARGUMENT'S LIFETIME INDEPENDENT OF IMPLEMENTATION *****/
// 1) lifetime parameter is explicitly specified
pub fn new_independent_lifetime<'b>(data: &'b str) -> Foo<'b> {
Foo { data }
}
// 2) elided lifetime, but still shown on the return type using the wildcard lifetime
// see: https://rust-lang.github.io/rfcs/2115-argument-lifetimes.html#the-wildcard-lifetime
// lifetime of return type is deduced to be the same as the lifetime of the argument
pub fn new_independent_lifetime_elided(data: &str) -> Foo<'_> {
Foo { data }
}
// 3) maximally elided lifetime, not even shown on the return type with the wildcard lifetime
// lifetime of return type is deduced to be the same as the lifetime of the argument
pub fn new_independent_lifetime_maximally_elided(data: &str) -> Foo {
Foo { data }
}
/***** CONSTRUCTORS WITH ARGUMENT'S LIFETIME TIED TO IMPLEMENTATION *****/
// 1) lifetime on the return type is explicitly specified to be the same as the lifetime of the argument
pub fn new_tied_lifetime(data: &'a str) -> Foo<'a> {
Foo { data }
}
// 2) lifetime on the return type expressed using the wildcard lifetime and inferred from the argument
pub fn new_tied_lifetime_wildcard(data: &'a str) -> Foo<'_> {
Foo { data }
}
// 3) lifetime on the return type elided and inferred from the argument
pub fn new_tied_lifetime_elided(data: &'a str) -> Foo {
Foo { data }
}
// 4) idiomatic, and the Self alias is the same as explicitly specifying Foo<'a>
pub fn new_tied_lifetime_idiomatic(data: &'a str) -> Self {
Self { data }
}
}
fn f<'short>(s: &'short str) {
// lifetime independent of implementation
let _: Foo<'short> = Foo::<'static>::new_independent_lifetime(s);
let _: Foo<'static> = Foo::<'short>::new_independent_lifetime("");
let _: Foo<'short> = Foo::<'static>::new_independent_lifetime_elided(s);
let _: Foo<'static> = Foo::<'short>::new_independent_lifetime_elided("");
let _: Foo<'short> = Foo::<'static>::new_independent_lifetime_maximally_elided(s);
let _: Foo<'static> = Foo::<'short>::new_independent_lifetime_maximally_elided("");
// lifeime tied to implementation
// NONE OF THE FOLLWING COMPILES
//let _: Foo<'short> = Foo::<'static>::new_tied_lifetime(s);
//let _: Foo<'static> = Foo::<'short>::new_tied_lifetime("");
//let _: Foo<'short> = Foo::<'static>::new_tied_lifetime_wildcard(s);
//let _: Foo<'static> = Foo::<'short>::new_tied_lifetime_wildcard("");
//let _: Foo<'short> = Foo::<'static>::new_tied_lifetime_elided(s);
//let _: Foo<'static> = Foo::<'short>::new_tied_lifetime_elided("");
//let _: Foo<'short> = Foo::<'static>::new_tied_lifetime_idiomatic(s);
//let _: Foo<'static> = Foo::<'short>::new_tied_lifetime_idiomatic("");
}