Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does a lifetime reference when declared in a trait implementation?

Tags:

rust

I'm learning about named lifetimes in Rust, and I'm having trouble understanding what they represent when they are used in the implementation of a trait. Specifically, I'm having trouble understanding this piece of code from libserialize/hex.rs. I've removed some comments for brevity's sake.

pub trait ToHex {
    fn to_hex(&self) -> ~str;
}

static CHARS: &'static[u8] = bytes!("0123456789abcdef");

impl<'a> ToHex for &'a [u8] {
    fn to_hex(&self) -> ~str {
        let mut v = slice::with_capacity(self.len() * 2);
        for &byte in self.iter() {
            v.push(CHARS[(byte >> 4) as uint]);
            v.push(CHARS[(byte & 0xf) as uint]);
        }

        unsafe {
             str::raw::from_utf8_owned(v)
        }
    }
}

I understand the 'static lifetime in the CHARS definition, but I'm stumped on the lifetime defined in the ToHex implementation. What do named lifetimes represent in the implementation of a trait?

like image 885
TwentyMiles Avatar asked Apr 15 '14 02:04

TwentyMiles


People also ask

What is lifetime in Rust?

Lifetimes are what the Rust compiler uses to keep track of how long references are valid for. Checking references is one of the borrow checker's main responsibilities. Lifetimes help the borrow checker ensure that you never have invalid references.

What is a named lifetime parameter in Rust?

Rust uses lifetime parameters to avoid such potential run-time errors. Since the compiler doesn't know in advance whether the if or the else block will execute, the code above won't compile and an error message will be printed that says, “a lifetime parameter is expected in compare 's signature.”

What are trait bounds in Rust?

Trait and lifetime bounds provide a way for generic items to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a where clause.

What is static lifetime Rust?

Static items have the static lifetime, which outlives all other lifetimes in a Rust program. Static items may be placed in read-only memory if the type is not interior mutable. Static items do not call drop at the end of the program.


1 Answers

In that particular case—not much. &[u8] is not a completely specified type because the lifetime is missing, and implementations must be for fully specified types. Thus, the implementation is parameterised over the arbitrary (for the generic parameter is unconstrained) lifetime 'a.

In this case, you don't use it again. There are cases where you will, however—when you wish to constrain a function argument or return value to the same lifetime.

You can then write things like this:

impl<'a, T> ImmutableVector<'a, T> for &'a [T] {
    fn head(&self) -> Option<&'a T> {
        if self.len() == 0 { None } else { Some(&self[0]) }
    }
    …
}

That means that the return value will have the same lifetime as self, 'a.

Incidentally, just to mess things up, the lifetime could be written manually on each function:

impl<'a, T> ImmutableVector<'a, T> for &'a [T] {
    fn head<'a>(&'a self) -> Option<&'a T> {
        if self.len() == 0 { None } else { Some(&self[0]) }
    }
    …
}

… and that demonstrates that having to specify the lifetime of the type that you are implementing for is just so that the type is indeed fully specified. And it allows you to write a little bit less for all the functions inside that use that lifetime.

like image 123
Chris Morgan Avatar answered Apr 27 '23 23:04

Chris Morgan