1 00:00:06,600 --> 00:00:07,980 - In the previous section, 2 00:00:07,980 --> 00:00:11,070 I described that a closure can capture a variable 3 00:00:11,070 --> 00:00:11,910 by reference, 4 00:00:11,910 --> 00:00:13,770 or by value. 5 00:00:13,770 --> 00:00:17,520 We're going to see how to capture by value in this section. 6 00:00:17,520 --> 00:00:18,353 But first of all, 7 00:00:18,353 --> 00:00:21,180 a quick recap of how capturing by reference works. 8 00:00:21,180 --> 00:00:23,070 So here look at this example. 9 00:00:23,070 --> 00:00:25,980 I've declared a string b1, 10 00:00:25,980 --> 00:00:26,813 I'm going to draw this, 11 00:00:26,813 --> 00:00:28,680 so you can kind of visualize what's going on. 12 00:00:28,680 --> 00:00:30,660 b1 is a string, 13 00:00:30,660 --> 00:00:32,493 which points to some text. 14 00:00:33,360 --> 00:00:36,150 The closure captures b1. 15 00:00:36,150 --> 00:00:38,070 It uses b1. 16 00:00:38,070 --> 00:00:41,700 So remember a closure is actually an object. 17 00:00:41,700 --> 00:00:43,710 When you write the closure, 18 00:00:43,710 --> 00:00:46,590 under the surface the compiler creates a class 19 00:00:46,590 --> 00:00:47,430 in an object, 20 00:00:47,430 --> 00:00:49,110 a closure object. 21 00:00:49,110 --> 00:00:52,590 And that closure object will have instance variables 22 00:00:52,590 --> 00:00:56,070 that give you the external state. 23 00:00:56,070 --> 00:01:00,480 So the compiler will generate a closure object 24 00:01:00,480 --> 00:01:04,560 which has a b1 instance variable. 25 00:01:04,560 --> 00:01:05,880 The compiler has to decide 26 00:01:05,880 --> 00:01:08,430 whether b1 should be a reference, 27 00:01:08,430 --> 00:01:11,880 or something else to the original string. 28 00:01:11,880 --> 00:01:14,880 And it depends on how you've used b1 in the closure. 29 00:01:14,880 --> 00:01:15,960 So in the closure here, 30 00:01:15,960 --> 00:01:18,930 you can see all I've done is to print it. 31 00:01:18,930 --> 00:01:21,720 And when you print a value, 32 00:01:21,720 --> 00:01:23,520 it just captures, 33 00:01:23,520 --> 00:01:26,520 it just basically does an immutable reference. 34 00:01:26,520 --> 00:01:29,010 So the compiler would basically set b1 35 00:01:29,010 --> 00:01:32,940 up as a as just a reference to the external string. 36 00:01:32,940 --> 00:01:35,700 So the lambda doesn't own the string 37 00:01:35,700 --> 00:01:37,500 it's just a reference to the string. 38 00:01:38,418 --> 00:01:41,970 And obviously after my closure's finished 39 00:01:41,970 --> 00:01:45,510 I can still access the original string in my main code. 40 00:01:45,510 --> 00:01:47,340 We still own b1. 41 00:01:47,340 --> 00:01:48,600 We haven't lost it, 42 00:01:48,600 --> 00:01:50,550 we captured by reference. 43 00:01:50,550 --> 00:01:53,520 Now, it's also possible to capture by value 44 00:01:53,520 --> 00:01:56,940 where instead of the closure being a reference 45 00:01:56,940 --> 00:02:01,920 it actually somehow copies the value itself. 46 00:02:01,920 --> 00:02:04,830 So capturing a variable by value 47 00:02:04,830 --> 00:02:08,730 this is necessary if the closure requires ownership 48 00:02:08,730 --> 00:02:09,600 of the object, 49 00:02:09,600 --> 00:02:11,040 not just a reference. 50 00:02:11,040 --> 00:02:14,430 So if there's something that you do inside your closure 51 00:02:14,430 --> 00:02:16,770 where it requires to own the object, 52 00:02:16,770 --> 00:02:18,320 not just to have a reference to it, 53 00:02:18,320 --> 00:02:23,320 in that case Rust will capture the variable by value. 54 00:02:23,970 --> 00:02:27,270 Rust will actually move ownership of the variable 55 00:02:27,270 --> 00:02:30,235 from the outside into the closure. 56 00:02:30,235 --> 00:02:32,160 After the closure body, 57 00:02:32,160 --> 00:02:35,070 the outer function can no longer access the variable. 58 00:02:35,070 --> 00:02:37,190 It loses ownership okay? 59 00:02:37,190 --> 00:02:38,910 So that's quite profound. 60 00:02:38,910 --> 00:02:42,420 The closure requires ownership of the variable 61 00:02:42,420 --> 00:02:44,880 and the external function can no longer access 62 00:02:44,880 --> 00:02:45,713 that variable. 63 00:02:45,713 --> 00:02:48,300 It's basically being given away into the closure, 64 00:02:48,300 --> 00:02:50,225 like a donation. 65 00:02:50,225 --> 00:02:52,950 So this is quite a tricky thing to imagine. 66 00:02:52,950 --> 00:02:55,080 I'm going to show you an example 67 00:02:55,080 --> 00:02:57,030 and I'm gonna draw a picture as well. 68 00:02:57,030 --> 00:02:59,280 So here we have a message string. 69 00:02:59,280 --> 00:03:01,050 So if I draw that here, 70 00:03:01,050 --> 00:03:06,050 message is a string object which contains hello like so 71 00:03:09,450 --> 00:03:11,614 and then I have a closure. 72 00:03:11,614 --> 00:03:12,480 And in the closure, 73 00:03:12,480 --> 00:03:14,190 it first of all prints message, 74 00:03:14,190 --> 00:03:15,420 fair enough. 75 00:03:15,420 --> 00:03:16,950 But also it calls this function here 76 00:03:16,950 --> 00:03:18,480 which you probably haven't seen before. 77 00:03:18,480 --> 00:03:20,100 In the standard crate, 78 00:03:20,100 --> 00:03:22,320 there's a module called mem. 79 00:03:22,320 --> 00:03:25,800 And in the mem module there's a function called drop. 80 00:03:25,800 --> 00:03:28,800 And when you pass an object into the drop function, 81 00:03:28,800 --> 00:03:32,640 it basically acquires ownership of that object. 82 00:03:32,640 --> 00:03:35,520 And at the end of the function it drops it. 83 00:03:35,520 --> 00:03:36,353 Okay? 84 00:03:36,353 --> 00:03:37,350 So whatever you pass, 85 00:03:37,350 --> 00:03:38,490 whatever object you pass 86 00:03:38,490 --> 00:03:41,280 into the drop function will be dropped 87 00:03:41,280 --> 00:03:45,120 or de allocated at the end of the drop function. 88 00:03:45,120 --> 00:03:45,953 Okay? 89 00:03:45,953 --> 00:03:46,786 So as you can see, 90 00:03:46,786 --> 00:03:48,990 the closure calls the drop function 91 00:03:48,990 --> 00:03:51,153 which requires ownership of message. 92 00:03:52,770 --> 00:03:53,670 Right? 93 00:03:53,670 --> 00:03:56,940 So let's think about what happens there. 94 00:03:56,940 --> 00:04:01,500 So if I draw my Lambda object here, 95 00:04:01,500 --> 00:04:03,810 it's accessing message. 96 00:04:03,810 --> 00:04:05,640 So the compiler has to decide 97 00:04:05,640 --> 00:04:08,790 whether the lambda should have a reference 98 00:04:08,790 --> 00:04:10,440 to the original message or 99 00:04:10,440 --> 00:04:13,320 whether it should be a copy of some sort. 100 00:04:13,320 --> 00:04:17,730 And because the drop function requires ownership of message, 101 00:04:17,730 --> 00:04:19,230 then the compiler will actually, 102 00:04:19,230 --> 00:04:21,750 create a whole string object here. 103 00:04:21,750 --> 00:04:22,620 It's like when you copy 104 00:04:22,620 --> 00:04:24,690 or when you assign one string to another. 105 00:04:24,690 --> 00:04:28,890 The lambda will actually be an assignment effectively, 106 00:04:28,890 --> 00:04:33,890 it'll copy the bit pointer into here 107 00:04:35,070 --> 00:04:36,810 and the original message declared 108 00:04:36,810 --> 00:04:40,413 in the external scope is kind of moved away. 109 00:04:41,400 --> 00:04:42,233 All right? 110 00:04:42,233 --> 00:04:43,500 So a move because very similar 111 00:04:43,500 --> 00:04:46,470 to when you pass an object by value into a function. 112 00:04:46,470 --> 00:04:50,310 The receiving function acquires ownership 113 00:04:50,310 --> 00:04:53,280 and the original variable is moved away. 114 00:04:53,280 --> 00:04:55,020 So after the closure, 115 00:04:55,020 --> 00:04:57,930 we can't use the original message anymore. 116 00:04:57,930 --> 00:05:00,000 We can't use this original message 117 00:05:00,000 --> 00:05:04,860 because its value has been moved away into the closure. 118 00:05:04,860 --> 00:05:08,640 When you have a closure that moves by value, 119 00:05:08,640 --> 00:05:10,080 you can't then use it. 120 00:05:10,080 --> 00:05:12,750 You can't then use that external variable anymore, 121 00:05:12,750 --> 00:05:14,130 afterwards. 122 00:05:14,130 --> 00:05:16,170 So let me run an example to show 123 00:05:16,170 --> 00:05:18,420 that in practice and we'll see the error messages you, 124 00:05:18,420 --> 00:05:19,683 you get if you try. 125 00:05:20,640 --> 00:05:23,820 Right so here's the code and in main I'm going 126 00:05:23,820 --> 00:05:28,050 to un-comment this statement here on line 18, 127 00:05:28,050 --> 00:05:30,903 demo closures where it captures a value. 128 00:05:31,830 --> 00:05:33,420 And then it's here. 129 00:05:33,420 --> 00:05:35,280 I've actually got two examples. 130 00:05:35,280 --> 00:05:37,290 I'm capturing a value automatically, 131 00:05:37,290 --> 00:05:38,820 which is what we're going to look at. 132 00:05:38,820 --> 00:05:41,700 And then just before we finish this section, 133 00:05:41,700 --> 00:05:44,550 we'll see how to capture a value forcibly. 134 00:05:44,550 --> 00:05:45,624 Okay? 135 00:05:45,624 --> 00:05:46,457 We'll ignore that for now 136 00:05:46,457 --> 00:05:48,240 and we'll just look at the main function 137 00:05:48,240 --> 00:05:49,560 and up here 138 00:05:49,560 --> 00:05:52,113 I'll comment out the second call. 139 00:05:53,310 --> 00:05:55,830 We'll just see how to capture a value automatically. 140 00:05:55,830 --> 00:05:57,180 Oh, and by the way, 141 00:05:57,180 --> 00:06:00,420 just to give my application a little bit of predictability, 142 00:06:00,420 --> 00:06:01,525 I have a sleep for 10 seconds at the end, 143 00:06:01,525 --> 00:06:05,880 just so that the application doesn't terminate too quickly 144 00:06:05,880 --> 00:06:07,200 for the discussion. 145 00:06:07,200 --> 00:06:08,220 Right so let's have a look 146 00:06:08,220 --> 00:06:10,050 at capturing a value automatically. 147 00:06:10,050 --> 00:06:12,840 Let's go through the code here carefully. 148 00:06:12,840 --> 00:06:13,800 I declare a message 149 00:06:13,800 --> 00:06:17,040 and I own the message and I print it. 150 00:06:17,040 --> 00:06:18,480 Fine. 151 00:06:18,480 --> 00:06:19,800 Here's my closure. 152 00:06:19,800 --> 00:06:22,260 The closure calls the drop function 153 00:06:22,260 --> 00:06:24,420 and the drop function the compiler will understand, 154 00:06:24,420 --> 00:06:26,370 requires ownership of message. 155 00:06:26,370 --> 00:06:29,910 So immediately the message object is moved away 156 00:06:29,910 --> 00:06:32,370 from here into my closure object. 157 00:06:32,370 --> 00:06:37,370 My closure object now owns message and I don't. 158 00:06:37,710 --> 00:06:41,100 So I can't use message after the closure. 159 00:06:41,100 --> 00:06:41,933 Okay? 160 00:06:41,933 --> 00:06:43,590 Its value has been donated into the closure. 161 00:06:43,590 --> 00:06:44,940 I've given it away. 162 00:06:44,940 --> 00:06:46,620 I can't use it again myself. 163 00:06:46,620 --> 00:06:47,940 If I tried to, 164 00:06:47,940 --> 00:06:49,470 let's see what would happen 165 00:06:49,470 --> 00:06:53,370 if I un-comment line 27, 166 00:06:53,370 --> 00:06:54,843 gonna get a compiler error. 167 00:06:57,390 --> 00:06:58,223 Right. 168 00:06:58,223 --> 00:06:59,056 cargo, 169 00:06:59,056 --> 00:07:00,453 I just do a cargo check. 170 00:07:02,310 --> 00:07:03,750 The error message is quite lengthy 171 00:07:03,750 --> 00:07:05,730 as we are kind of used to now. 172 00:07:05,730 --> 00:07:07,623 So it kind of goes on a bit. 173 00:07:08,580 --> 00:07:10,680 But the essence of the problem, 174 00:07:10,680 --> 00:07:13,500 the actual error is on line 27. 175 00:07:13,500 --> 00:07:15,870 I can't use message 176 00:07:15,870 --> 00:07:19,710 because it's already been moved away basically. 177 00:07:19,710 --> 00:07:23,520 And it mentions the drop function here. 178 00:07:23,520 --> 00:07:26,160 Because the drop function requires ownership, 179 00:07:26,160 --> 00:07:30,420 then the message was moved into the closure. 180 00:07:30,420 --> 00:07:32,910 So it's been moved away from here. 181 00:07:32,910 --> 00:07:36,930 I can't use message afterwards, right? 182 00:07:36,930 --> 00:07:38,820 Well, so you have to be careful, 183 00:07:38,820 --> 00:07:42,270 if you have a closure that requires a movement 184 00:07:42,270 --> 00:07:43,710 which doesn't happen that often, 185 00:07:43,710 --> 00:07:46,620 but it can you can't then use the original variable 186 00:07:46,620 --> 00:07:48,213 after the closure. 187 00:07:49,320 --> 00:07:51,900 There's another error message that we could get though, 188 00:07:51,900 --> 00:07:55,473 if we tried to call the consume message more than once. 189 00:07:56,331 --> 00:07:59,940 So I'll call the consume message function the first time. 190 00:07:59,940 --> 00:08:01,044 Okay? 191 00:08:01,044 --> 00:08:03,090 Which will cause the message to be dropped. 192 00:08:03,090 --> 00:08:05,670 I can't call it a second time. 193 00:08:05,670 --> 00:08:08,320 Let's see what happened if I did try to call it twice 194 00:08:09,750 --> 00:08:10,860 Cargo check. 195 00:08:10,860 --> 00:08:13,360 I'm gonna get a different error message this time. 196 00:08:15,690 --> 00:08:17,010 So on line, 197 00:08:17,010 --> 00:08:22,010 the error is actually on line 33 leading up to the error. 198 00:08:23,970 --> 00:08:25,650 It said on line 30, 199 00:08:25,650 --> 00:08:27,510 you called the closure. 200 00:08:27,510 --> 00:08:31,053 And because the closure required ownership of message, 201 00:08:32,130 --> 00:08:33,393 a movement occurred. 202 00:08:34,650 --> 00:08:37,680 And if you then try to call consume message again, 203 00:08:37,680 --> 00:08:39,630 well what would happen if it let me do that? 204 00:08:39,630 --> 00:08:42,180 The first time I called consume message, 205 00:08:42,180 --> 00:08:44,100 it would basically drop the message. 206 00:08:44,100 --> 00:08:46,350 The message object no longer exists. 207 00:08:46,350 --> 00:08:48,720 And if I then tried to call the consume message again, 208 00:08:48,720 --> 00:08:50,310 it would be trying to use the message 209 00:08:50,310 --> 00:08:52,680 that's already been dropped from the first call. 210 00:08:52,680 --> 00:08:54,570 So in Rust, 211 00:08:54,570 --> 00:08:57,240 we have the concept of closures, 212 00:08:57,240 --> 00:08:59,280 that can only be invoked once 213 00:08:59,280 --> 00:09:01,020 because when you call them, 214 00:09:01,020 --> 00:09:04,350 you kind of destroy the context. 215 00:09:04,350 --> 00:09:06,960 You drop external variables. 216 00:09:06,960 --> 00:09:09,723 So you can only call this closure once. 217 00:09:10,560 --> 00:09:14,280 I'm gonna explain the concept in detail later on. 218 00:09:14,280 --> 00:09:16,290 It's to do with traits. 219 00:09:16,290 --> 00:09:17,520 It says here, 220 00:09:17,520 --> 00:09:21,720 that the closure implements a trait called fn once. 221 00:09:21,720 --> 00:09:23,610 So I'll explain what that means later on. 222 00:09:23,610 --> 00:09:27,120 If you ever have a closure that implements fn once 223 00:09:27,120 --> 00:09:29,640 it means you can only call it once. 224 00:09:29,640 --> 00:09:32,160 Okay that's technically a bit more complicated than that 225 00:09:32,160 --> 00:09:33,840 but then that's what it boils down to. 226 00:09:33,840 --> 00:09:35,340 So be careful. 227 00:09:35,340 --> 00:09:38,190 If you have a closure that acquires, 228 00:09:38,190 --> 00:09:42,120 captures a variable and then owns it and destroys it, 229 00:09:42,120 --> 00:09:46,260 you can't use that variable afterwards and you 230 00:09:46,260 --> 00:09:49,350 which means this statement wouldn't work. 231 00:09:49,350 --> 00:09:50,490 Have to call that one out. 232 00:09:50,490 --> 00:09:51,690 And you can't call the, 233 00:09:51,690 --> 00:09:54,600 the closure twice either. 234 00:09:54,600 --> 00:09:57,150 So anyway having commented those lines out, 235 00:09:57,150 --> 00:09:59,043 I think it should now work okay. 236 00:09:59,940 --> 00:10:00,993 Fingers crossed. 237 00:10:02,790 --> 00:10:06,810 So up here the message initially was displayed, 238 00:10:06,810 --> 00:10:10,890 hello and then I called the closure 239 00:10:10,890 --> 00:10:13,140 which prints the message again hello, 240 00:10:13,140 --> 00:10:15,060 and then drops it. 241 00:10:15,060 --> 00:10:16,380 There was a delay at the end, 242 00:10:16,380 --> 00:10:17,583 and then it terminated. 243 00:10:18,780 --> 00:10:23,370 Okay so that's capturing a value automatically. 244 00:10:23,370 --> 00:10:25,440 And what we're gonna look at to just wrap 245 00:10:25,440 --> 00:10:29,640 up the demo is we'll see how to capture a value forcibly. 246 00:10:29,640 --> 00:10:32,496 Okay so I'll just get my demo ready 247 00:10:32,496 --> 00:10:35,700 and we'll have a look at the theory first 248 00:10:35,700 --> 00:10:38,700 and then we'll run the demo to see what happens in practice.