Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does changing a field from `&'a [u8]` to `&'a mut [u8]` cause a lifetime error?

Tags:

rust

This code compiles:

struct BufRef<'a> {
    buf: &'a [u8],
}

struct Foo<'a> {
    buf_ref: BufRef<'a>,
}

impl<'a> Iterator for Foo<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        let result = &self.buf_ref.buf;
        Some(result)
    }
}

However, if I change BufRef to:

struct BufRef<'a> {
    buf: &'a mut [u8],
}

The compiler says:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src\main.rs:13:16
   |
13 |         let result = &self.buf_ref.buf;
   |                      ^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
  --> src\main.rs:12:5
   |
12 | /     fn next(&mut self) -> Option<Self::Item> {
13 | |         let result = &self.buf_ref.buf;
14 | |         Some(result)
15 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src\main.rs:13:16
   |
13 |         let result = &self.buf_ref.buf;
   |                      ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 9:6...
  --> src\main.rs:9:6
   |
9  | impl<'a> Iterator for Foo<'a> {
   |      ^^
   = note: ...so that the types are compatible:
           expected std::iter::Iterator
              found std::iter::Iterator

Why does changing the field to &'a mut [u8] cause the error?

Also, what does the compiler mean by this:

...so that the types are compatible:
               expected std::iter::Iterator
                  found std::iter::Iterator
like image 724
Shmoopy Avatar asked Sep 08 '19 18:09

Shmoopy


People also ask

What happens if I change field type in Salesforce?

If you convert an auto-number field into a text field, the data in that field remains unchanged. Also, you can safely convert a text custom field into an auto-number field without losing your data. Converting an auto-number field into any other data type results in data loss.

What are the consequences of changing field size?

The effect of changing the field size depends on whether the field already contains data. If the field does not contain data When you change the field size, the size of new data values is limited for the field.

How do you change the field type?

Select the field (the column) that you want to change. On the Fields tab, in the Properties group, click the arrow in the drop-down list next to Data Type, and then select a data type. Save your changes.

Can you change the field type of a field if it is referenced in Apex?

You won't be able to change the field type if: It is referenced in your Apex code or any other custom code you've written.


1 Answers

I think that what is misleading you is that your code has a collapsed reference.

Your next function is basically equivalent to this code:

fn next(&mut self) -> Option<&'a [u8]> {
    let result: &&'a [u8] = &self.buf_ref.buf;
    Some(result)
}

This works because the double reference collapses to a single reference. In this case the double reference only obfuscates the code. Just write:

fn next(&mut self) -> Option<Self::Item> {
    Some(self.buf_ref.buf)
}

And this works because references are always Copy.

But now what happens when you change your definition to &'a mut? You are probably guessing right now... mutable references are not Copy, so the same simple code will give you an easy-to-read error message:

cannot move out of self.buf_ref.buf which is behind a mutable reference

Naturally, you can reborrow a mutable ref as a const one, and then try to return it, but unfortunately this will not work because the the re-borrow cannot use the same lifetime as the mutable variable, it must be strictly smaller (or you could alias the pointed values). The compiler assigns the lifetime of this re-borrow as that of the next function, but now you cannot return this borrow, because it is a local reference!

Unfortunately, I don't know of any safe way to make your code compile. In fact I'm quite sure that it would create an unsound API. That is, if you managed to compile your code, then this safe code would create undefined behavior:

fn main() {
    let mut buf = vec![1,2,3];
    let buf_ref = BufRef { buf: &mut buf };
    let mut foo = Foo { buf_ref };
    let x: &[u8] = foo.next().unwrap();
    //note that x's lifetime is that of buf, foo is not borrowed
    //x and foo.buf_ref.buf alias the same memory!
    //but the latter is mutable    
    println!("{}", x[0]); //prints 1
    foo.buf_ref.buf[0] = 4;
    println!("{}", x[0]); //prints what?
}
like image 94
rodrigo Avatar answered Oct 17 '22 16:10

rodrigo