1 00:00:06,020 --> 00:00:11,900 And this lecture we are going to talk about lifetimes, and it is important to note that every reference 2 00:00:11,900 --> 00:00:13,010 has a lifetime. 3 00:00:13,370 --> 00:00:17,210 Most of the time, lifetimes are implicit and inferred. 4 00:00:17,540 --> 00:00:21,050 Some would say that this is rust most distinctive feature. 5 00:00:21,380 --> 00:00:25,360 The main idea behind lifetimes is to prevent dangling references. 6 00:00:25,370 --> 00:00:27,980 So let's set up a quick dangling reference. 7 00:00:28,160 --> 00:00:34,100 So we're going to say let are and then we're going to open up another code block and say let x equals 8 00:00:34,100 --> 00:00:40,790 five, and then we're going to assign a reference of X to R, and then we're going to come down here 9 00:00:40,790 --> 00:00:51,770 and we want to try and print out R So if we run this, we see that it says the borrowed value does not 10 00:00:51,770 --> 00:00:55,490 live long enough because X is dropped here. 11 00:00:58,540 --> 00:01:09,130 And then here we try to reference ah which ah we tried to use ah which was a reference to x, but x 12 00:01:09,130 --> 00:01:09,880 is no longer there. 13 00:01:09,880 --> 00:01:15,520 So we have a dangling reference now and this is where lifetime annotations start to help us think through 14 00:01:15,520 --> 00:01:20,560 this code and it helps the rest compiler find these dangling references for us ahead of time. 15 00:01:20,920 --> 00:01:27,880 So as we dive into what lifetime annotations are, it is important to know that lifetime annotations 16 00:01:27,880 --> 00:01:31,540 do not change how long any of the references live. 17 00:01:31,630 --> 00:01:38,890 Lifetime annotations just describe the relationships of the lifetimes of multiple references to each 18 00:01:38,890 --> 00:01:42,520 other without actually affecting their lifetime. 19 00:01:43,290 --> 00:01:48,140 So to set up a lifetime, all we have to do is just use a tick. 20 00:01:48,150 --> 00:01:55,140 So one, one single quote and then a you do not have to use an A, but that is what most people will 21 00:01:55,140 --> 00:01:55,740 do. 22 00:01:56,970 --> 00:01:59,850 So we can do a reference. 23 00:02:01,640 --> 00:02:03,260 To an integer 32. 24 00:02:04,310 --> 00:02:12,920 We can have a reference with an explicit lifetime setup of an I 32 and then we can have a reference 25 00:02:14,360 --> 00:02:18,080 that is immutable with an explicit lifetime. 26 00:02:18,470 --> 00:02:23,690 So let's look at a quick function and just try to make a little bit more sense about this. 27 00:02:24,530 --> 00:02:29,600 So we're going to just call it an example function, assign here the lifetime. 28 00:02:31,010 --> 00:02:39,380 And then inside we're going to have a parameter of X that's going to be a reference with an explicit 29 00:02:39,380 --> 00:02:42,380 lifetime stated. 30 00:02:42,950 --> 00:02:46,070 And then we're also going to return. 31 00:02:48,660 --> 00:02:51,620 An explicit lifetime string slice. 32 00:02:51,630 --> 00:02:58,560 So what we can see here is that the lifetime annotations. 33 00:02:59,940 --> 00:03:06,540 Indicate that the reference X must both must live as long as the generic lifetime. 34 00:03:06,540 --> 00:03:15,870 So we can see that all the function, the functions using the same lifetime, annotation, the parameters, 35 00:03:15,870 --> 00:03:18,600 using it, and also the string slice. 36 00:03:19,230 --> 00:03:27,600 So the function signatures going to tell us that for some lifetime of tick a the the function takes 37 00:03:27,600 --> 00:03:32,700 parameter X which is a string slice and it must live. 38 00:03:33,420 --> 00:03:37,590 As at least as long as the lifetime of take. 39 00:03:37,620 --> 00:03:45,150 A So when we're returning a reference from a function, the lifetime parameter for the return type needs 40 00:03:45,150 --> 00:03:48,600 to match the lifetime for one of the parameters. 41 00:03:48,600 --> 00:03:56,160 So what the lifetime being returned here must match at least one parameter being passed in which in 42 00:03:56,160 --> 00:03:57,840 this case we do satisfy. 43 00:03:59,030 --> 00:03:59,570 So. 44 00:04:00,530 --> 00:04:02,510 What exactly are the life times? 45 00:04:02,510 --> 00:04:03,680 Why did they start? 46 00:04:04,590 --> 00:04:06,030 And why are they in Rust? 47 00:04:06,030 --> 00:04:08,670 Because it is a very unique feature. 48 00:04:09,710 --> 00:04:16,460 So the history behind lifetimes has evolved as Rus has evolved. 49 00:04:16,610 --> 00:04:23,630 So as we've done in past examples, we have had functions that have had references as parameters and 50 00:04:23,630 --> 00:04:25,580 a reference returned at the end of the function. 51 00:04:25,580 --> 00:04:29,360 But we did not have to specify a lifetime annotation. 52 00:04:29,510 --> 00:04:31,670 So why were we able to do that? 53 00:04:31,760 --> 00:04:36,980 Well, the reason to this is actually based on the history of Russ and earlier versions of Russ. 54 00:04:36,980 --> 00:04:43,820 The Russ team noticed that programmers were entering the same lifetime annotations constantly, so they 55 00:04:43,820 --> 00:04:49,100 were able to add these patterns into the compiler so the borrow checker could infer these lifetimes 56 00:04:49,100 --> 00:04:53,360 in certain situations and would no longer need explicit annotations. 57 00:04:54,100 --> 00:04:59,950 Knowing this, the rust language might continue to see these patterns added into the compiler, which 58 00:04:59,950 --> 00:05:04,780 will allow programmers to less often add in these explicit lifetime annotations. 59 00:05:04,990 --> 00:05:11,600 So far, the compiler uses three rules to infer these lifetimes when there aren't explicit annotations. 60 00:05:11,620 --> 00:05:16,780 The first rule is that each parameter that is a reference gets its own lifetime parameter. 61 00:05:16,930 --> 00:05:23,380 So if we have one parameter, we have one lifetime parameter to K, but if we have two parameters, 62 00:05:23,380 --> 00:05:25,360 then we have two lifetime parameters. 63 00:05:25,360 --> 00:05:28,030 So we can have tick A and tick B. 64 00:05:28,390 --> 00:05:37,660 So just to make that clear, we can have to A for one parameter and then we can have tick B for second 65 00:05:38,800 --> 00:05:39,460 parameter. 66 00:05:42,340 --> 00:05:43,150 Then it continues on. 67 00:05:43,160 --> 00:05:45,670 So if you have three, you have pixie and so on. 68 00:05:46,270 --> 00:05:53,260 But the second rule is, if there is exactly one input lifetime parameter, that lifetime is assigned 69 00:05:53,260 --> 00:05:59,200 to all output lifetime parameters aka the lifetime is assigned to the return value. 70 00:06:00,040 --> 00:06:07,270 Lastly, the third rule is if there are multiple input lifetime parameters, but one of them is a reference 71 00:06:07,270 --> 00:06:10,660 to a to the self or a immutable self. 72 00:06:11,710 --> 00:06:19,090 And because in that case it is a method, the lifetime of self is assigned to all output life parameters. 73 00:06:19,330 --> 00:06:24,610 So lifetime annotations aren't typically needed in methods because it's always going to return the lifetime 74 00:06:24,610 --> 00:06:25,240 of self. 75 00:06:26,960 --> 00:06:32,090 So let's take a look at an example of why we need lifetime annotations. 76 00:06:32,090 --> 00:06:34,370 So we'll do another little one. 77 00:06:34,370 --> 00:06:36,680 We'll just kind of modify the one above. 78 00:06:38,380 --> 00:06:43,780 And we'll say Tick B and then we'll bring in Y. 79 00:06:46,970 --> 00:06:50,180 Take be that as a string and then. 80 00:06:55,790 --> 00:06:59,360 Expected a lifetime parameter so we can either return. 81 00:07:02,670 --> 00:07:04,890 A lifetime of X. 82 00:07:05,460 --> 00:07:08,400 Or we can return the lifetime of B. 83 00:07:08,400 --> 00:07:11,700 But if we do that, notice how X is now squiggly here. 84 00:07:11,700 --> 00:07:15,000 And it is saying the light, there's a lifetime mismatch. 85 00:07:15,000 --> 00:07:24,030 So that's kind of so what we're looking at here is the first rule being applied because we have two 86 00:07:24,030 --> 00:07:25,470 lifetime parameters. 87 00:07:25,890 --> 00:07:31,470 But you can see that the second rule doesn't apply because there is more than one input lifetime because 88 00:07:31,470 --> 00:07:36,270 we have ticked B and then since there is no cell, the third rule does not apply. 89 00:07:36,270 --> 00:07:42,480 But we have to have a lifetime annotation on the return value because there was one given to the parameters. 90 00:07:42,480 --> 00:07:48,720 And as we learned earlier, when returning a reference from a function, the lifetime parameter for 91 00:07:48,720 --> 00:07:52,740 the return type needs to match the lifetime for one of the parameters. 92 00:07:52,740 --> 00:07:59,400 So lifetime annotations are required in situations where the borrow checker doesn't know what to infer. 93 00:07:59,400 --> 00:08:06,090 And it's important because we want the borrow checker to ensure that we have memory safety.