What difference between Self and the struct name produces this error? - rust

This code works fine:
#[derive(Debug)]
struct Foo<'a> {
data: Vec<&'a str>,
}
impl Foo<'_> {
fn bar_func(arg1: &str) {
let f = Foo { data : arg1.split_whitespace().collect() };
println!("{:?}", f.data);
}
}
fn main() {
Foo::bar_func(&"hey split me!");
}
But if I change Foo for Self when creating the struct:
fn bar_func(arg1: &str) {
let f = Self { data : arg1.split_whitespace().collect() };
println!("{:?}", f.data);
}
I get a lifetime error:
error: lifetime may not live long enough
--> src/main.rs:9:31
|
6 | impl Foo<'_> {
| -- lifetime `'2` appears in the `impl`'s self type
7 |
8 | fn bar_func(arg1: &str) {
| - let's call the lifetime of this reference `'1`
9 | let f = Self { data : arg1.split_whitespace().collect() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
= note: requirement occurs because of the type `SplitWhitespace<'_>`, which makes the generic argument `'_` invariant
= note: the struct `SplitWhitespace<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Until now I assumed that these would be interchangeable, and I tend to use Self most of the time, so you can imagine, this got me stuck for a very long time, and it was just luck how I found that it worked fine with the struct name when trying to isolate the problem in a minimal example.
Are they not equivalent, and if so, what is the difference?

They're not the same.
Foo is Foo<'_>, with inferred (or elided) lifetime, and that means we can use the lifetime of arg1.
Self, however, keeps generic parameters of the current type, and that includes lifetimes. Thus, the lifetime of Foo with Self refer to the elided '_ in impl Foo<'_>, which is a distinct generic lifetime that is incompatible with arg1's lifetime.

Related

Rust - Lifetimes - Understanding Lifetime Error for mutable reference to self

I'm sure this is a duplicate, but I can't find a question which matches my question, exactly since I have a couple extra requirements because I have to adhere to some traits that I can't control.
Here is my code. I apologize for the sort of convoluted example, but this was the most I could minimize it as I am trying to implement a custom serialization format using the serde library.
// Doesn't really matter what this struct contains, it just needs an owning method
struct SideStruct;
impl SideStruct {
fn something_side<A: TraitA>(&self, aval: A) {
println!("something sideways :)");
aval.something_a(42)
}
}
trait TraitA {
fn something_a(&mut self, data: u32); // this would be the meat of my logic
}
// Note that this struct has an explicit lifetime
struct MainStruct<'a> {
refr: &'a mut u32
}
// Note that I implement for a mutable reference to MainStruct
impl<'a> TraitA for &'a mut MainStruct<'a> {
fn something_a(&mut self, data: u32) {
// Completely arbitrary, can safely ignore this function body
*self.refr += data;
println!("We're finally doing something: {}", self.refr);
}
}
// Implementing for MainStruct itself
impl<'a> MainStruct<'a> {
// Note, I can't change the signature for this function because it implements a trait
fn something_indirect(&mut self, ss: &SideStruct) {
// here is where the error occurs!
ss.something_side(self)
}
}
fn main() {
let mut base_val: u32 = 42;
let ss = SideStruct {};
let mut main_val = MainStruct { refr: &mut base_val };
main_val.something_indirect(&ss);
}
This is the error I got:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:27
|
28 | ss.something_side(self)
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/main.rs:27:27
|
27 | fn something_indirect(&mut self, ss: &SideStruct) {
| ^^^^^^^^^
note: ...so that the expression is assignable
--> src/main.rs:28:27
|
28 | ss.something_side(self)
| ^^^^
= note: expected `&mut MainStruct<'a>`
found `&mut MainStruct<'a>`
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:26:6
|
26 | impl<'a> MainStruct<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:28:12
|
28 | ss.something_side(self)
| ^^^^^^^^^^^^^^
= note: expected `<&mut MainStruct<'a> as TraitA>`
found `<&mut MainStruct<'_> as TraitA>`
For more information about this error, try `rustc --explain E0495`.
I don't know what the compiler means when it states that note: first, the lifetime cannot outlive the anonymous lifetime defined here.... Does it mean that some constraint forces self to not outlast the method something_indirect? That makes no sense. Also the message so that the expression is assignable confuses me. MainStruct should not be assigned when something_side is called on it right? Since I implemented TraitA for a mutable reference to MainStruct, shouldn't I be able to call something_side with a mutable reference to MainStruct by passing self? Anyways, thanks for the help, and have a great day!
The trouble is that in order to use the method defined, you must borrow the MainStruct as mutable with an anonymous lifetime. In the code you wrote, you not only borrow the things within MainStruct for 'a, but also MainStruct itself. This is unnecessary since the borrow has an inferred lifetime. You can fix this by removing the 'a in the trait impl
impl<'a> TraitA for &mut MainStruct<'a> {
/*...*/
}
This should do the exact same thing, but removes the bug. The bug is trying to tell you that the code you wrote is buggy, because it borrows MainStruct using a lifetime in the struct itself.

Returning a higher-kinded closure that captures a reference

I'm trying to write a method on a struct that returns a closure. This closure should take a &[u8] with an arbitrary lifetime 'inner as an argument and return the same type, &'inner [u8]. To perform its function, the closure also needs a (shared) reference to a member of the struct &self. Here is my code:
#![warn(clippy::pedantic)]
// placeholder for a large type that I can't afford to clone
struct Opaque(usize);
struct MyStruct<'a>(Vec<&'a Opaque>);
impl<'a> MyStruct<'a> {
pub fn get_func_for_index(
&'a self,
n: usize,
) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
// the reference to the struct member, captured by the closure
let opaque: &'a Opaque = *self.0.get(n)?;
Some(move |i: &[u8]| {
// placeholder: do something with the input using the &Opaque
&i[opaque.0..]
})
}
}
fn main() {
let o1 = Opaque(1);
let o5 = Opaque(5);
let o7 = Opaque(7);
let x = MyStruct(vec![&o1, &o5, &o7]);
let drop_five = x.get_func_for_index(1 /*Opaque(5)*/).unwrap();
let data: Vec<u8> = Vec::from(&b"testing"[..]);
assert_eq!(drop_five(&data[..]), b"ng");
}
If I try to compile it with rustc 1.54.0 (a178d0322 2021-07-26), I get the following error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> /tmp/lifetimes.rs:16:14
|
16 | &i[opaque.0..]
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 14:14...
--> /tmp/lifetimes.rs:14:14
|
14 | Some(move |i: &[u8]| {
| ______________^
15 | | // placeholder: do something with the input using the &Opaque
16 | | &i[opaque.0..]
17 | | })
| |_________^
note: ...so that reference does not outlive borrowed content
--> /tmp/lifetimes.rs:16:14
|
16 | &i[opaque.0..]
| ^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 6:6...
--> /tmp/lifetimes.rs:6:6
|
6 | impl<'a> MyStruct<'a> {
| ^^
note: ...so that return value is valid for the call
--> /tmp/lifetimes.rs:10:17
|
10 | ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: higher-ranked subtype error
--> /tmp/lifetimes.rs:7:5
|
7 | / pub fn get_func_for_index(
8 | | &'a self,
9 | | n: usize,
10 | | ) -> Option<impl for<'inner> Fn(&'inner [u8]) -> &'inner [u8] + 'a> {
| |_______________________________________________________________________^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0495`.
It's quite a mouthful and I don't really understand what it's trying to tell me. The first part (first, the lifetime...) makes sense to me, the returned slice must not outlive the closure argument. The second part (but, the lifetime...) however seems weird to me - the + 'a annotation in the method signature refers to the closure itself (because it captures &'a self.foo), not to the value the closure returns.
Is it possible to change the code to model this correctly in rust, or is this construct just not supported at this time?
The problem is here:
Some(move |i: &[u8]| {
Every & has a lifetime on it, explicit or not. What is the lifetime of &[u8]? Clearly it should be "a lifetime chosen by the caller of the closure" (that is, a higher-ranked lifetime). But when the compiler encounters a reference type with a free lifetime parameter, even in the argument list of a closure, it will not assume that the lifetime is higher-ranked. The error message you get about the "anonymous lifetime #1" is the compiler confusedly trying to make a non-higher-ranked lifetime work.
The compiler could, in theory, work "backwards" from the impl Fn in the return type and recognize that the type of the closure needs to have this higher ranked lifetime. It's not quite clever enough to do that in this case, but there is a way to convince it: use a local function with a bounded type parameter to constrain the type of the closure to exactly the bound you want.
pub fn get_func_for_index(
&self, // note 1
n: usize,
) -> Option<impl 'a + for<'inner> Fn(&'inner [u8]) -> &'inner [u8]> { // note 2
// the reference to the struct member, captured by the closure
let opaque: &'a Opaque = *self.0.get(n)?;
// helper function to constrain the closure type
fn check<F: Fn(&[u8]) -> &[u8]>(f: F) -> F { // note 3
f
}
Some(check(move |i| {
// placeholder: do something with the input using the &Opaque
&i[opaque.0..]
}))
}
Playground
Please note the following:
&'a self is too conservative for this function because 'a is the lifetime parameter of the reference self contains, not the lifetime for which self is borrowed. In general, you should almost never write &'a self or &'a mut self where 'a is a named lifetime from an outer scope.
I find the + 'a easy to miss at the end of a long trait, especially a Fn trait with a return type. I recommend fronting the lifetime (putting it first) in cases like this to make clear that it relates more to the impl than to the &'inner [u8]. This is a stylistic choice.
Fn(&[u8]) -> &[u8] is actually exactly the same as for<'inner> Fn(&'inner [u8]) -> &'inner [u8], because the elision rules for Fn traits are the same as for regular functions. Either way is fine; I find the shorter version easier to read.
Similar questions
Expected bound lifetime parameter, found concrete lifetime [E0271]
How to declare a higher-ranked lifetime for a closure argument?
Why does this closure require inlining or `dyn`? What does `dyn` do here?

HRTB: Concrete type bounded by a trait containing lifetime type parameter vs bounded by only a lifetime type parameter

This is actually an offshoot of this SO question.
Consider the following code:
trait Trait<'b> {
fn func(&'b self) {}
}
struct Struct {}
impl<'s> Trait<'s> for Struct {}
fn test<'s, T:'s>(t: T)
where
T: Trait<'s>,
{
t.func();
}
It fails, as the compiler sees that t lives for less than the 's and 's is set by the caller (i.e longer than the stack-frame of the func) and traits are invariant over type parameters. However, if I introduce HRTB (Higher Rank Trait Bounds) here, the code compiles:
fn test<T>(t: T)
where
T: for<'s> Trait<'s>,
{
t.func();
}
Now, the trait Trait<'s> is implemented for all possible lifetimes 's represents and accordingly the right one gets picked by the compiler.
But then why the following code fails ?
struct Temp<'a> {
x: &'a i32,
}
fn test<T>(t: T)
where
for<'s> T: 's,
{
}
fn main() {
let d = 1i32;
test(Temp { x: &d });
}
It gives the error:
error[E0597]: `d` does not live long enough
--> src/main.rs:13:20
|
13 | test(Temp { x: &d });
| ---------------^^---
| | |
| | borrowed value does not live long enough
| argument requires that `d` is borrowed for `'static`
14 | }
| - `d` dropped here while still borrowed
What is the difference here? Conceptually, I found the earlier example same as this one. Why it is expected that the concrete type T should only be/contain reference(s) with 'static lifetime(s) ?

Can I limit the lifetime pollution from a struct?

I have a struct which contains some stuff. I implement the Iterator trait for that struct, and return a tuple of references to internal data in the struct. That necessitates that I annotate at least some things with lifetimes. What I want is to minimize the lifetime annotation, especially when it comes to other structs which have the original struct as a member.
some code:
pub struct LogReader<'a> {
data:String,
next_fn:fn(&mut LogReader)->Option<(&'a str,&'a [ConvertedValue])>,
//...
}
pub struct LogstreamProcessor {
reader: LogReader, // doesn't work without polluting LogstreamProcessor with lifetimes
//...
}
impl<'a> Iterator for LogReader<'a > {
type Item = (&'a str,&'a[ConvertedValue]);
fn next(&mut self) -> Option<(&'a str,&'a[ConvertedValue])>{(self.next_fn)(self)}
}
impl <'a> LogReader<'a> {
pub fn new(textFile:Option<bool>) -> LogReader<'a> {
LogReader {
next_fn:if textFile.unwrap_or(false) { LogReader::readNextText }else{ LogReader::readNextRaw },
data: "blah".to_string()
}
}
fn readNextText(&mut self)->Option<(&str,&[ConvertedValue])>{unimplemented!();}
fn readNextRaw(&mut self)->Option<(&str,&[ConvertedValue])>{unimplemented!();}
}
Can I limit the lifetime pollution from a struct?
Generically, if you're using them in any of your struct's fields, then you can't. They are made explicit for very good reasons (see Why are explicit lifetimes needed in Rust?), and once you have a struct containing objects that require explicit lifetimes, then they must be propagated.
Note that usually this isn't a concern to consumers of the struct, since the concrete lifetimes are then imposed by the compiler:
struct NameRef<'a>(&'a str);
let name = NameRef("Jake"); // 'a is 'static
One could also slightly mitigate the "noise" on the implementation of next by using the definition of Self::Item.
impl<'a> Iterator for LogReader<'a > {
type Item = (&'a str,&'a[ConvertedValue]);
fn next(&mut self) -> Option<Self::Item> {
(self.next_fn)(self)
}
}
However, your concern actually hides a more serious issue: Unlike you've mentioned, the values returned from next are not necessarily internal data from the struct. They actually live for as long as the generic lifetime 'a, and nothing inside LogReader is actually bound by that lifetime.
This means two things:
(1) I could pass a function that gives something completely different, and it would work just fine:
static NO_DATA: &[()] = &[()];
fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
Some(("wat", NO_DATA))
}
(2) Even if I wanted my function to return something from the log reader's internal data, it wouldn't work because the lifetimes do not match at all. Let's try it out anyway to see what happens:
static DATA: &[()] = &[()];
fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
Some((&reader.data[0..4], DATA))
}
fn main() {
let mut a = LogReader {
data: "This is DATA!".to_owned(),
next_fn: my_next_fn
};
println!("{:?}", a.next());
}
The compiler would throw you this:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:26:12
|
26 | Some((&reader.data[0..4], DATA))
| ^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 25:88...
--> src/main.rs:25:89
|
25 | fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
| _________________________________________________________________________________________^ starting here...
26 | | Some((&reader.data[0..4], DATA))
27 | | }
| |_^ ...ending here
note: ...so that reference does not outlive borrowed content
--> src/main.rs:26:12
|
26 | Some((&reader.data[0..4], DATA))
| ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 25:88...
--> src/main.rs:25:89
|
25 | fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> {
| _________________________________________________________________________________________^ starting here...
26 | | Some((&reader.data[0..4], DATA))
27 | | }
| |_^ ...ending here
note: ...so that expression is assignable (expected std::option::Option<(&'a str, &'a [()])>, found std::option::Option<(&str, &[()])>)
--> src/main.rs:26:5
|
26 | Some((&reader.data[0..4], DATA))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...where the anonymous lifetime #1 is the log reader's lifetime. Forcing &mut LogReader to also have a lifetime 'a (&'a mut LogReader<'a>) would lead to further lifetime issues when attempting to implement Iterator. This basically narrows down to the fact that 'a is incompatible with references to values of LogReader themselves.
So, how should we fix that?
but that doesn't change the fact that the return type has references and so lifetime annotations come into it
Although that is not accurate (since lifetime elision can occur in some cases), that gives a hint to the solution: either avoid returning references at all or delegate data to a separate object, so that 'a can be bound to that object's lifetime. The final part of the answer to your question is in Iterator returning items by reference, lifetime issue.

Restrict lifetime parameter to scope of parameters of a function

Consider the following example
trait MyTrait<'a> {
type N: 'a;
fn func(&'a self) -> Self::N;
}
fn myfunc<'a, T: 'a + MyTrait<'a>>(g: T) {
g.func();
}
fn main() {}
Compiling this small program fails with:
error[E0597]: `g` does not live long enough
--> src/main.rs:8:5
|
8 | g.func();
| ^ borrowed value does not live long enough
9 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 7:1...
--> src/main.rs:7:1
|
7 | fn myfunc<'a, T: 'a + MyTrait<'a>>(g: T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As far as I understand, the lifetime parameter 'a is not restricted and could be arbitrary. However, g is a parameter and its lifetime is only the function scope, therefore it does not satisfy the condition of lifetime 'a in the definition of method func.
What I really want is that the associated type N is always restricted to the lifetime of self in MyTrait. That's why I came up with the explicit lifetime parameter 'a of MyTrait. I want function myfunc to work, i.e. 'a should somehow be restricted to the lifetime of of the parameter g.
What is the "correct" way to solve this problem?
A very simple example is
struct MyPtr<'a> {
x: &'a usize,
}
struct MyStruct {
data: Vec<usize>,
}
impl<'a> MyTrait<'a> for MyStruct {
type N = MyPtr<'a>;
fn func(&'a self) -> Self::N {
MyPtr { x: &self.data[0] }
}
}
Note that this is extremely simplified, of course. The idea is that N always contains a reference to something contained in MyTrait and should therefore never outlive MyTrait.
What you want is not to bind a generic lifetime, but to allow "any" lifetime:
fn myfunc<T: for<'a> MyTrait<'a>>(g: T) {
g.func();
}
Fully working example in the playground.
The best source for an explanation is How does for<> syntax differ from a regular lifetime bound?.

Resources