1 00:00:06,570 --> 00:00:10,260 - When we started this lesson, we looked at nested functions 2 00:00:10,260 --> 00:00:12,300 and then we looked at closures. 3 00:00:12,300 --> 00:00:14,280 And I explained that one of the big differences 4 00:00:14,280 --> 00:00:16,590 between a nested function and a closure 5 00:00:16,590 --> 00:00:19,110 is that a closure can access variables 6 00:00:19,110 --> 00:00:21,030 defined in the outer scope. 7 00:00:21,030 --> 00:00:22,440 And that's what we're going to look at now. 8 00:00:22,440 --> 00:00:25,440 It's known as capturing, and here's the basic idea. 9 00:00:25,440 --> 00:00:29,280 I've got an outer function, which declares some variables. 10 00:00:29,280 --> 00:00:30,780 I've got a closure. 11 00:00:30,780 --> 00:00:34,140 And that closure can access captured variables. 12 00:00:34,140 --> 00:00:38,430 It can access variables defined in the outer scope like so. 13 00:00:38,430 --> 00:00:41,640 Okay, so that's called capturing, and it's very useful. 14 00:00:41,640 --> 00:00:44,730 It allows this closure to benefit from information 15 00:00:44,730 --> 00:00:46,380 defined in the external scope. 16 00:00:46,380 --> 00:00:49,593 You can use these variables inside the Lambda. 17 00:00:50,520 --> 00:00:53,610 Okay, and you can't do that with nested functions. 18 00:00:53,610 --> 00:00:56,850 So, how does capturing work with closures? 19 00:00:56,850 --> 00:00:58,860 Basically what the compiler will do 20 00:00:58,860 --> 00:01:02,340 is it'll decide what mechanism to use 21 00:01:02,340 --> 00:01:03,660 to capture the variables 22 00:01:03,660 --> 00:01:07,530 depending on how you've used them in your closure. 23 00:01:07,530 --> 00:01:10,770 In your closure, if you've used an external variable, 24 00:01:10,770 --> 00:01:12,360 the compiler will either capture it 25 00:01:12,360 --> 00:01:14,280 as an immutable reference 26 00:01:14,280 --> 00:01:17,970 if you don't change it and don't need ownership. 27 00:01:17,970 --> 00:01:19,980 Or it'll capture the external variable 28 00:01:19,980 --> 00:01:23,490 as a mutable reference if you are changing it. 29 00:01:23,490 --> 00:01:27,990 Or under certain circumstances, it'll capture by value. 30 00:01:27,990 --> 00:01:29,490 And that's quite tricky. 31 00:01:29,490 --> 00:01:30,750 Basically what that means 32 00:01:30,750 --> 00:01:33,870 is that the external function had a variable, 33 00:01:33,870 --> 00:01:37,680 but ownership gets transferred into the closure. 34 00:01:37,680 --> 00:01:40,140 So, the closure now owns the variable 35 00:01:40,140 --> 00:01:42,360 which means you can't then use it anymore 36 00:01:42,360 --> 00:01:44,040 in the external function. 37 00:01:44,040 --> 00:01:45,412 Okay, so that's a bit tricky. 38 00:01:45,412 --> 00:01:47,910 We'll have a look at that later. 39 00:01:47,910 --> 00:01:52,910 So, the idea is the Rust compiler looks in your closure. 40 00:01:53,310 --> 00:01:55,440 It sees how you've used the variable 41 00:01:55,440 --> 00:01:58,110 and that's how it decides how to do the capturing. 42 00:01:58,110 --> 00:02:00,390 So, we'll have a look at capturing references first 43 00:02:00,390 --> 00:02:01,740 because they're easier. 44 00:02:01,740 --> 00:02:04,560 And then, later we'll have a look at how to capture values. 45 00:02:04,560 --> 00:02:07,170 And we'll discuss all the kind of implications 46 00:02:07,170 --> 00:02:10,080 in terms of ownership in that case. 47 00:02:10,080 --> 00:02:13,377 So, here's an example of capturing a variable 48 00:02:13,377 --> 00:02:16,410 as an immutable reference. 49 00:02:16,410 --> 00:02:19,680 So from the top, I've declared a string b1. 50 00:02:19,680 --> 00:02:20,880 It's like a banner. 51 00:02:20,880 --> 00:02:23,820 And it displays the top part of a banner. 52 00:02:23,820 --> 00:02:26,160 And I've got another string b2 53 00:02:26,160 --> 00:02:29,460 which displays the bottom part of a banner. 54 00:02:29,460 --> 00:02:34,164 And I've got a closure, which uses b1, and it uses b2. 55 00:02:34,164 --> 00:02:37,410 It displays a heading with a nice banner around it. 56 00:02:37,410 --> 00:02:39,870 It also takes a string as a parameter. 57 00:02:39,870 --> 00:02:41,250 I call it twice. 58 00:02:41,250 --> 00:02:45,750 First of all, I pass in "hello" into the string. 59 00:02:45,750 --> 00:02:50,460 And then, second time I pass "goodbye" into the string. 60 00:02:50,460 --> 00:02:51,570 So, let's see what happens. 61 00:02:51,570 --> 00:02:53,580 When I call the closure the first time, 62 00:02:53,580 --> 00:02:56,310 I pass in "hello" into s. 63 00:02:56,310 --> 00:03:00,990 At that point, my closure is going to print b1 64 00:03:00,990 --> 00:03:04,530 Now, when you print something, print borrows immutably. 65 00:03:04,530 --> 00:03:06,060 It doesn't change the value. 66 00:03:06,060 --> 00:03:07,500 It's an immutable borrow. 67 00:03:07,500 --> 00:03:11,280 So, the compiler will realize that our closure 68 00:03:11,280 --> 00:03:14,763 needs to capture an immutable reference to b1. 69 00:03:15,750 --> 00:03:18,210 So, effectively it looks like this. 70 00:03:18,210 --> 00:03:20,160 The compiler will capture 71 00:03:20,160 --> 00:03:23,280 an immutable reference to b1, okay? 72 00:03:23,280 --> 00:03:25,786 And then, it'll display the heading, 73 00:03:25,786 --> 00:03:30,723 this kind of upper banner here. 74 00:03:31,664 --> 00:03:33,540 Then, it displays the string, 75 00:03:33,540 --> 00:03:37,050 whatever I pass into the string, I passed "hello" into s. 76 00:03:37,050 --> 00:03:42,050 So, it prints kind of like side pipes 77 00:03:42,390 --> 00:03:44,070 and then it prints the string 78 00:03:44,070 --> 00:03:47,640 in a field with the 15 characters, left aligned. 79 00:03:47,640 --> 00:03:50,370 And then finally, I've borrowed b2. 80 00:03:50,370 --> 00:03:52,560 And again, this is an immutable borrow. 81 00:03:52,560 --> 00:03:56,253 So, the compiler will capture b2 immutably. 82 00:03:57,300 --> 00:03:58,170 Okay? 83 00:03:58,170 --> 00:04:01,380 Now what actually happens internally is quite interesting. 84 00:04:01,380 --> 00:04:04,710 Closures internally are objects. 85 00:04:04,710 --> 00:04:07,080 And when you capture an external variable, 86 00:04:07,080 --> 00:04:10,050 they become instance variables inside that object. 87 00:04:10,050 --> 00:04:14,550 So, this closure here actually gets converted into a class 88 00:04:14,550 --> 00:04:17,310 and that class will have an instance variable 89 00:04:17,310 --> 00:04:18,520 to capture b1 90 00:04:19,980 --> 00:04:24,120 and that will be an immutable reference like so. 91 00:04:24,120 --> 00:04:26,160 And when it sees, when the compiler sees 92 00:04:26,160 --> 00:04:30,120 that you've used b2, it'll add b2 as an instance variable 93 00:04:30,120 --> 00:04:31,450 into the closure object 94 00:04:32,430 --> 00:04:35,880 as a immutable reference to b2 like that. 95 00:04:35,880 --> 00:04:38,310 And then, when you invoke the closure, 96 00:04:38,310 --> 00:04:39,780 it basically kind of calls, 97 00:04:39,780 --> 00:04:42,750 it's similar to the way it works in C++. 98 00:04:42,750 --> 00:04:47,100 If you've looked at operator parenthesis in C++, 99 00:04:47,100 --> 00:04:49,710 it's a similar kind of mechanism to that. 100 00:04:49,710 --> 00:04:52,500 When you call a closure, it'll basically invoke the code 101 00:04:52,500 --> 00:04:55,080 that you specified to print the message 102 00:04:55,080 --> 00:05:00,080 and using b1 and b2 to access the external variables 103 00:05:00,540 --> 00:05:02,940 as immutable references. 104 00:05:02,940 --> 00:05:04,740 All right, so one other thing 105 00:05:04,740 --> 00:05:06,960 and then I'm gonna run the example. 106 00:05:06,960 --> 00:05:11,160 Here, a reference is sufficient. 107 00:05:11,160 --> 00:05:15,210 The closure hasn't claimed ownership of b1 and b2. 108 00:05:15,210 --> 00:05:17,190 They're just references. 109 00:05:17,190 --> 00:05:21,387 So, the external function still owns b1 and b2, 110 00:05:21,387 --> 00:05:25,013 and can still use b1 and b2 afterwards, okay? 111 00:05:25,013 --> 00:05:26,970 We haven't lost ownership. 112 00:05:26,970 --> 00:05:29,640 We've just, they've just been borrowed by the closure 113 00:05:29,640 --> 00:05:32,007 but the outer function still owns b1 and b2 114 00:05:32,007 --> 00:05:34,200 and can still use them. 115 00:05:34,200 --> 00:05:38,250 Okay, so let's run the example to show that in practice. 116 00:05:38,250 --> 00:05:40,200 So, here's the example. 117 00:05:40,200 --> 00:05:42,450 In the main code, 118 00:05:42,450 --> 00:05:45,390 I'm gonna un-comment this part of the demo, 119 00:05:45,390 --> 00:05:46,990 demo_closures_capture_reference. 120 00:05:48,900 --> 00:05:49,950 Very good. 121 00:05:49,950 --> 00:05:53,335 And it's here. 122 00:05:53,335 --> 00:05:54,840 So, I've got two functions. 123 00:05:54,840 --> 00:05:55,673 The first function 124 00:05:55,673 --> 00:05:57,960 is what we're going to look at first of all, 125 00:05:57,960 --> 00:06:01,860 where I've got my b1 and b2 strings. 126 00:06:01,860 --> 00:06:05,613 My closure, which captures b1 as an immutable reference. 127 00:06:05,613 --> 00:06:08,700 It's all kind of implicit really. 128 00:06:08,700 --> 00:06:11,130 You just have to read between the lines 129 00:06:11,130 --> 00:06:14,790 and understand that b1 will be captured by the closure 130 00:06:14,790 --> 00:06:17,670 as an immutable reference and printed. 131 00:06:17,670 --> 00:06:19,230 Then, it'll print the string. 132 00:06:19,230 --> 00:06:23,040 Then, it'll print b2 which is the bottom part of my banner. 133 00:06:23,040 --> 00:06:25,710 And that's my closure, which will print a banner 134 00:06:25,710 --> 00:06:28,140 for "hello" and a banner for "goodbye." 135 00:06:28,140 --> 00:06:30,990 And then just to emphasize that the outer function 136 00:06:30,990 --> 00:06:33,810 can still access b1 and b2 afterwards. 137 00:06:33,810 --> 00:06:36,826 The closure hasn't claimed ownership of b1 and b2. 138 00:06:36,826 --> 00:06:40,230 It's just borrowed the values via references, 139 00:06:40,230 --> 00:06:42,780 immutable references in this case. 140 00:06:42,780 --> 00:06:46,170 So in my main code, I've got two calls. 141 00:06:46,170 --> 00:06:47,070 The one we're looking at here 142 00:06:47,070 --> 00:06:48,620 is capture_immutable_reference. 143 00:06:49,500 --> 00:06:50,333 We'll have a look 144 00:06:50,333 --> 00:06:52,650 at capturing mutable reference a bit later. 145 00:06:52,650 --> 00:06:54,360 So, let's just ignore that for now. 146 00:06:54,360 --> 00:06:56,670 Let's just comment that statement out. 147 00:06:56,670 --> 00:06:59,370 And we'll just run the first part of the example. 148 00:06:59,370 --> 00:07:00,900 I was quite pleased with this example actually 149 00:07:00,900 --> 00:07:02,820 when I decided how I was going to do it. 150 00:07:02,820 --> 00:07:05,403 It looks quite nice, cargo run. 151 00:07:07,890 --> 00:07:08,850 Okay. 152 00:07:08,850 --> 00:07:13,260 So, it displayed the heading for "hello" 153 00:07:13,260 --> 00:07:15,630 which meant displaying b1 154 00:07:15,630 --> 00:07:18,090 which is the top part of the banner. 155 00:07:18,090 --> 00:07:20,100 And then, displaying "hello" 156 00:07:20,100 --> 00:07:21,570 and then the bottom part of the banner. 157 00:07:21,570 --> 00:07:24,570 So, there's hello in the bottom part of the banner., 158 00:07:24,570 --> 00:07:28,050 And then, I repeated it to display the goodbye banner. 159 00:07:28,050 --> 00:07:32,460 So, b1 goodbye, and that's the end of b2. 160 00:07:32,460 --> 00:07:36,840 And then, just it prints b1 and b2 on separate lines here, 161 00:07:36,840 --> 00:07:38,850 just to confirm that we can still access 162 00:07:38,850 --> 00:07:41,430 b1 and b2 if we want to. 163 00:07:41,430 --> 00:07:45,690 So, because this closure captured b1 and b2, 164 00:07:45,690 --> 00:07:47,670 but it didn't need to change them, 165 00:07:47,670 --> 00:07:51,453 b1 and b2 will be captured as immutable references. 166 00:07:52,500 --> 00:07:53,333 Good. 167 00:07:53,333 --> 00:07:54,270 What we're gonna look at next 168 00:07:54,270 --> 00:07:56,670 is how to capture multiple references. 169 00:07:56,670 --> 00:07:59,220 So, let me just rearrange my demo. 170 00:07:59,220 --> 00:08:02,730 Let's discuss the theory and then we'll run the demo again. 171 00:08:02,730 --> 00:08:05,130 Okay, so have a look at this example. 172 00:08:05,130 --> 00:08:07,392 First of all, note that b1 and b2 are mutable. 173 00:08:07,392 --> 00:08:10,620 They could potentially be changed anywhere. 174 00:08:10,620 --> 00:08:12,300 And in my closure, 175 00:08:12,300 --> 00:08:15,990 if you want to change a captured variable, 176 00:08:15,990 --> 00:08:17,940 then you have to declare the closure itself 177 00:08:17,940 --> 00:08:19,860 has to be multiple. 178 00:08:19,860 --> 00:08:21,450 Right. Okay. 179 00:08:21,450 --> 00:08:24,060 So, my mutable, sorry my closure 180 00:08:24,060 --> 00:08:27,510 is allowed to change external variables. 181 00:08:27,510 --> 00:08:28,764 And it does. 182 00:08:28,764 --> 00:08:31,830 b1, it captures by reference, 183 00:08:31,830 --> 00:08:33,870 but it's gonna change b1. 184 00:08:33,870 --> 00:08:38,340 It's going to append a tick mark at the end of b1. 185 00:08:38,340 --> 00:08:41,520 Okay, so first of all, obviously b1 has to be mutable. 186 00:08:41,520 --> 00:08:44,880 And because I want to change b1 in my closure, 187 00:08:44,880 --> 00:08:48,060 then the closure itself has to be mutable. 188 00:08:48,060 --> 00:08:51,060 So, what'll happen is, again, 189 00:08:51,060 --> 00:08:53,553 internally when you have a closure, 190 00:08:54,450 --> 00:08:57,840 internally it is actually a class one object. 191 00:08:57,840 --> 00:09:00,911 And when you access b1, 192 00:09:00,911 --> 00:09:02,340 it'll basically access, 193 00:09:02,340 --> 00:09:06,540 it'll in my Lambda object, it'll basically create b1 194 00:09:06,540 --> 00:09:11,540 as a mutable reference to this string here. 195 00:09:11,670 --> 00:09:14,262 And then, obviously when I capture b2, 196 00:09:14,262 --> 00:09:18,723 it'll capture b2 also as a multiple reference. 197 00:09:20,880 --> 00:09:23,850 Okay, so there we go. 198 00:09:23,850 --> 00:09:28,350 So, when I call the function, my Lambda I should say. 199 00:09:28,350 --> 00:09:31,780 The first time I pass "hello" as the string 200 00:09:33,510 --> 00:09:36,930 and it appends a tick mark at the end of b1. 201 00:09:36,930 --> 00:09:38,880 I just draw a tick mark there. 202 00:09:38,880 --> 00:09:41,700 And it appends a tick mark at the end of b2 203 00:09:41,700 --> 00:09:43,140 I'll put a tick mark there. 204 00:09:43,140 --> 00:09:46,380 And then it prints the banner as it currently looks. 205 00:09:46,380 --> 00:09:50,760 And then, I call, I just tidy my diagram up a little bit. 206 00:09:50,760 --> 00:09:53,190 And then I call the closure a second time, 207 00:09:53,190 --> 00:09:55,770 and this time I pass in "goodbye." 208 00:09:55,770 --> 00:09:59,250 So that string gets passed into this, into s. 209 00:09:59,250 --> 00:10:02,640 And then it depends, another tick mark into b1 210 00:10:02,640 --> 00:10:04,470 and another tick mark into b2. 211 00:10:04,470 --> 00:10:06,540 So, it has actually changed the value 212 00:10:06,540 --> 00:10:08,550 in the external banners. 213 00:10:08,550 --> 00:10:12,270 And then, it prints goodbye with those banners. 214 00:10:12,270 --> 00:10:13,770 And then at the end, just to show 215 00:10:13,770 --> 00:10:17,880 that we still own b1 and b2 in our external code, 216 00:10:17,880 --> 00:10:21,310 we can then print out b1 and b2 separately. 217 00:10:21,310 --> 00:10:25,830 And they will have changed by the closure. 218 00:10:25,830 --> 00:10:27,840 Let's run that example. 219 00:10:27,840 --> 00:10:29,340 So, capture_mutable_reference. 220 00:10:31,050 --> 00:10:33,000 Here's the code that we just looked at. 221 00:10:34,560 --> 00:10:37,953 Let me just tidy up my output and run it again. 222 00:10:42,360 --> 00:10:47,360 Okay, so b1 was originally that banner. 223 00:10:47,640 --> 00:10:51,750 When I call the closure the first time to print "hello", 224 00:10:51,750 --> 00:10:55,050 it'll add a tick mark at the end of b1 and b2, 225 00:10:55,050 --> 00:10:56,520 and then print out the message. 226 00:10:56,520 --> 00:11:01,320 So, b1 has a tick mark, and b2 has a tick mark. 227 00:11:01,320 --> 00:11:04,140 I call the closure a second time with "goodbye". 228 00:11:04,140 --> 00:11:07,890 It adds another tick mark, so that's two tick marks. 229 00:11:07,890 --> 00:11:11,100 So, b1 now has two tick marks. 230 00:11:11,100 --> 00:11:15,003 And b2 also has two tick marks. 231 00:11:15,900 --> 00:11:17,130 So, at the end of the code 232 00:11:17,130 --> 00:11:20,250 when I print off b1 and b2 at the end, 233 00:11:20,250 --> 00:11:23,916 you can see that they have indeed been changed 234 00:11:23,916 --> 00:11:27,060 by the closure, and this is absolutely fine. 235 00:11:27,060 --> 00:11:31,440 It's perfectly reasonable for a closure to be mutable 236 00:11:31,440 --> 00:11:34,030 and to change the external state, okay? 237 00:11:34,030 --> 00:11:35,790 Don't feel nervous about that. 238 00:11:35,790 --> 00:11:37,140 That's perfectly allowable. 239 00:11:37,140 --> 00:11:40,740 Just remember that if you do want your closure 240 00:11:40,740 --> 00:11:42,990 to mutate captive state, 241 00:11:42,990 --> 00:11:45,600 the closure must be defined as mutable, okay? 242 00:11:45,600 --> 00:11:46,850 Otherwise, it won't work.