// Lifetimes are another kind of generic that ensure the references are valid as long as// they need to be. Usually the lifetimes are implicit and inferred, but we need to// annotate them whenever lifetimes of references can be related in a few different ways.// ############################################################// Without the lifetime annotations the code won't compile. The help text in the error states:// this function's return type contains a borrowed value, but the signature does not say whether// it is borrowed from `x` or `y`// It basically states that the we don't know for sure whether the reference we return is of x// or is of y, we also don't know the relationship between the lifetimes of x and y, so we can't// guranttee whether the returned reference would remain valid for the required duration or not.// By adding the lifetime paramters we define this relationship and allow the borrow checker to// perform it's analysis.// Lifetime annotations don't change how long any of the references lives. Rather, they define the// relationships of lifetimes of different references with eachother without affecting the// lifetimes.// This signature with lifetime paramters tells Rust that the returned reference is valid as long// as both the parameters are valid.fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y }}fn main() { let result = longest("abcd", "xyzpqrs"); println!("Longest is: {}", result); let phrase = String::from("I am not a King. I am not a God. I am worse."); // String.split(delimeter) returns an iterator which contains elements separated // by delimeter. let parts = phrase.split('.'); for part in parts { println!("part ---> {}", part); } // The iterator maintains an internal cursor, essentially at which postion (or on // which element) the iterator is currently on. // Iterator.next returns the value at the current position of the internal cursor // and advances the internal cursor to the next position. The returned value is // wrapped in Some of and Option<> since, when the cursor is at the last element, // there is no next element so next() will return None of Option<>. // Hence this returns the first sentence of phrase. let sentence = phrase.split('.').next().unwrap(); let i = ImportantExcerpt { part: sentence }; println!("{}", i); static_demo(); println!("{}", i.level()); // Means, "Sundar ladki tum un gore ladkon ka kya karogi, un gore gore ladkon ka kya karogi." i.bolkar_wapis_kardo("Billo bagge bileya da ki karegi, bagge bagge bileya di ki karegi."); let p1 = "Daddy ji de cash ute kari jave aish sada bapu zimidar kitho laike daive car."; let p2 = "Devil'an de naal na tu khed nakhro, vardaat hundi da pata ni lagnaa."; let longest2 = longest_with_announcement(p1, p2, i); println!("Result: {}", longest2);}fn static_demo() { // Will remain valid throughout the scope of the program. // Text here is stored in the program's binary and so is always available (not neccesarily // accessible outside it's scope). All string literals have this reference let _s: &'static str = "I am inevitable.";}// Structs can also hold references, but we will need to specify the lifetime parameters.struct ImportantExcerpt<'a> { part: &'a str }impl std::fmt::Display for ImportantExcerpt<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "ImportantExcerpt({})", self.part) }}// Lifetime names for struct fields are always declared after impl and then used after the// struct's name as those lifetimes are part of the struct's type.impl<'a> ImportantExcerpt<'a> { fn level(&self) -> i32 { 69 } // example where 3rd lifetime elision rule applies fn bolkar_wapis_kardo(&self, samachar: &str) -> &str { println!("Yaatrigan krpya dhyaan dijiye: {}", samachar); self.part }}// Lifetime Elision Rules// These are patterns and rules built into the rust compiler that allow it// to infer the lifetime parameters in common situations and environments.// Lifetimes on function or method parameters are called Input Lifetimes and// those on return types are known as Output Lifetimes.// The following rules are used by the compiler. These apply to fn and impl blocks// RULE - 1 --> Compiler assigns a lifetime parameter to each parameter that's a reference.// RULE - 2 --> If there is exactly one input lifetime paramter then that lifetime is// assigned to all the output lifetimes.// RULE - 3 --> If there are multiple input lifetime parameters, but one of them is// &self or &mut self because this is a method, the lifetime of self is assigned to all// output lifetime parameters.// Example with everythingfn longest_with_announcement<'a, T>( x: &'a str, y: &'a str, ann: T) -> &'a strwhere T: std::fmt::Display{ println!("Announcement: {}", ann); if x.len() > y.len() { x } else { y }}