1 00:00:06,570 --> 00:00:09,420 - You can pass a closure into a function. 2 00:00:09,420 --> 00:00:11,610 The closure specifies an algorithm 3 00:00:11,610 --> 00:00:13,660 that you would like a function to invoke. 4 00:00:14,520 --> 00:00:17,760 So in the function that receives the closure, 5 00:00:17,760 --> 00:00:21,300 you specify what type of closure you expect to receive 6 00:00:21,300 --> 00:00:22,200 and you do that 7 00:00:22,200 --> 00:00:25,803 via the three trait types, FnOnce, FnMut, and Fn. 8 00:00:27,930 --> 00:00:29,430 So the incoming function, 9 00:00:29,430 --> 00:00:31,500 it has a type constraint to say 10 00:00:31,500 --> 00:00:35,610 give me a closure based on one of those three trait types. 11 00:00:35,610 --> 00:00:37,020 So let's see how this works. 12 00:00:37,020 --> 00:00:38,280 We'll have a look at an example 13 00:00:38,280 --> 00:00:41,457 of a function that receives an FnOnce 14 00:00:41,457 --> 00:00:43,920 and then a function that receives an FnMut. 15 00:00:43,920 --> 00:00:46,470 And then thirdly, a function that receives an Fn. 16 00:00:46,470 --> 00:00:48,330 Three different types of closure 17 00:00:48,330 --> 00:00:50,010 that you can pass into a function. 18 00:00:50,010 --> 00:00:51,660 Okay, so first of all, 19 00:00:51,660 --> 00:00:55,293 imagine a function that receives an FnOnce closure. 20 00:00:56,670 --> 00:01:00,570 So if your function receives a closure 21 00:01:00,570 --> 00:01:03,660 and only plans to call the closure once, 22 00:01:03,660 --> 00:01:06,690 then your function should be generic. 23 00:01:06,690 --> 00:01:08,730 It receives a function parameter 24 00:01:08,730 --> 00:01:11,760 and that function parameter should be of type FnOnce. 25 00:01:11,760 --> 00:01:13,530 It looks like this. 26 00:01:13,530 --> 00:01:14,880 I've got a function, 27 00:01:14,880 --> 00:01:18,570 whatever you wanna call it, I've called it receive_fnonce. 28 00:01:18,570 --> 00:01:21,060 It's a generic function, 29 00:01:21,060 --> 00:01:22,200 it has a type parameter. 30 00:01:22,200 --> 00:01:24,483 I've called it F as in function. 31 00:01:25,320 --> 00:01:27,900 So the idea is you pass some kind of function in here 32 00:01:27,900 --> 00:01:31,360 or to be more specific, you pass in a closure 33 00:01:32,250 --> 00:01:36,090 and that type parameter F must be some type, 34 00:01:36,090 --> 00:01:38,910 which implements FnOnce, okay? 35 00:01:38,910 --> 00:01:42,960 This is how you specify it implements FnOnce. 36 00:01:42,960 --> 00:01:46,470 This here is the signature of a closure. 37 00:01:46,470 --> 00:01:50,520 It represents a closure that takes no parameters 38 00:01:50,520 --> 00:01:52,620 and returns no value. 39 00:01:52,620 --> 00:01:54,180 So when you call this function, 40 00:01:54,180 --> 00:01:58,140 when you call receive once, you gotta pass in a closure 41 00:01:58,140 --> 00:02:00,900 and that closure must have this signature. 42 00:02:00,900 --> 00:02:03,960 It can be any closure that takes no parameters 43 00:02:03,960 --> 00:02:05,403 and doesn't return anything. 44 00:02:06,660 --> 00:02:09,900 So func is gonna be such a closure. 45 00:02:09,900 --> 00:02:14,283 We only call it once in here, so that's fine. 46 00:02:16,260 --> 00:02:20,400 Right, so I can pass in when I call receive_fnonce, 47 00:02:20,400 --> 00:02:22,620 I can pass in any kind of closure, 48 00:02:22,620 --> 00:02:26,520 any kind of function that implements the FnOnce straight, 49 00:02:26,520 --> 00:02:30,660 all closures implement FnOnce. 50 00:02:30,660 --> 00:02:34,170 So I can pass any kind of closure into this function as long 51 00:02:34,170 --> 00:02:37,410 as it has the signature that it takes no parameters 52 00:02:37,410 --> 00:02:38,960 and it doesn't return anything. 53 00:02:39,870 --> 00:02:43,710 Right, of course, when you have inheritance, 54 00:02:43,710 --> 00:02:48,710 if you have a function that receives type A, remember, well, 55 00:02:50,850 --> 00:02:52,920 let's say we've got an inheritance hierarchy 56 00:02:52,920 --> 00:02:54,033 that looks like this. 57 00:02:55,685 --> 00:02:58,320 A function that specifies it can receive type A, 58 00:02:58,320 --> 00:02:59,940 you can pass in, according to the list 59 00:02:59,940 --> 00:03:02,610 of substitution principle, you can pass in A 60 00:03:02,610 --> 00:03:04,563 or anything which inherits from A. 61 00:03:06,300 --> 00:03:09,690 So if you kind of imagine the same situation here 62 00:03:09,690 --> 00:03:13,290 in terms of closures, with closures, 63 00:03:13,290 --> 00:03:16,080 we have an inheritance hierarchy of traits. 64 00:03:16,080 --> 00:03:19,530 We have FnOnce and then inheriting from that, 65 00:03:19,530 --> 00:03:23,940 we have FnMut, and then inheriting from that, 66 00:03:23,940 --> 00:03:27,720 we have Fn as we discussed in the previous section. 67 00:03:27,720 --> 00:03:31,713 So a function that can receive an FnOnce, 68 00:03:33,360 --> 00:03:35,310 effectively, that's kind of what we've got. 69 00:03:35,310 --> 00:03:38,100 It can receive one of those objects 70 00:03:38,100 --> 00:03:42,360 or a lambda or closure, which implements FnMut or a closure, 71 00:03:42,360 --> 00:03:43,440 which implements Fn. 72 00:03:43,440 --> 00:03:47,133 Any kind of these closures can be passed in to here. 73 00:03:48,909 --> 00:03:50,790 So we're gonna have a look at that example, first of all, 74 00:03:50,790 --> 00:03:51,990 before we go any further. 75 00:03:51,990 --> 00:03:55,080 In the usual demo project, we'll have a look at main 76 00:03:55,080 --> 00:03:58,257 and then we'll have look at demo_closures_fnonce 77 00:03:58,257 --> 00:03:59,373 and we'll run it. 78 00:04:00,240 --> 00:04:01,740 Okay? So here we are. 79 00:04:01,740 --> 00:04:03,033 Here's my main code. 80 00:04:03,989 --> 00:04:07,470 I'm gonna run three separate demos in this section. 81 00:04:07,470 --> 00:04:10,410 First of all, a demo of closures 82 00:04:10,410 --> 00:04:13,740 that receive an FnOnce parameter. 83 00:04:13,740 --> 00:04:18,603 Let's uncomment that that, and let's see the code. 84 00:04:19,470 --> 00:04:21,840 Okay, so I've got several things I need to explain here. 85 00:04:21,840 --> 00:04:22,920 I'm gonna have three demos 86 00:04:22,920 --> 00:04:24,930 and they're all gonna be kind of similar to each other 87 00:04:24,930 --> 00:04:26,910 so I just need to explain it once. 88 00:04:26,910 --> 00:04:31,170 First of all, here's a function and it's generic. 89 00:04:31,170 --> 00:04:34,950 It receives some kind of parameter of type F 90 00:04:34,950 --> 00:04:37,710 where F must be a closure. 91 00:04:37,710 --> 00:04:39,780 FnOnce means it's a closure. 92 00:04:39,780 --> 00:04:42,390 A closure that takes no parameters 93 00:04:42,390 --> 00:04:44,460 and doesn't return anything. 94 00:04:44,460 --> 00:04:47,130 If you wanted to receive a closure that took an integer 95 00:04:47,130 --> 00:04:49,530 and return the Boolean, then you'd write this kind 96 00:04:49,530 --> 00:04:52,420 of syntax, a closure that takes an int32 97 00:04:53,820 --> 00:04:57,063 as a parameter and returns a Boolean. 98 00:04:58,500 --> 00:04:59,970 Okay, that kind of syntax. 99 00:04:59,970 --> 00:05:02,100 This here indicates the signature 100 00:05:02,100 --> 00:05:04,440 of the closure that you're passing in. 101 00:05:04,440 --> 00:05:07,110 So if you just write this, it means I want 102 00:05:07,110 --> 00:05:10,200 to have any closure which implements FnOnce, 103 00:05:10,200 --> 00:05:13,380 which basically means any closure that takes no parameters 104 00:05:13,380 --> 00:05:14,430 and doesn't return anything. 105 00:05:14,430 --> 00:05:18,213 And I only call the function once, so that's fine. 106 00:05:19,620 --> 00:05:24,620 So a function that receives an FnOnce parameter 107 00:05:24,870 --> 00:05:27,420 can receive any kind of closure. 108 00:05:27,420 --> 00:05:31,020 So I've called this function three times in the code below. 109 00:05:31,020 --> 00:05:35,850 I've called the function once, twice, three times. 110 00:05:35,850 --> 00:05:38,643 The first time, have a look at this closure here. 111 00:05:39,720 --> 00:05:41,250 That closure will be converted 112 00:05:41,250 --> 00:05:45,150 into a structure by Rust and that structure, 113 00:05:45,150 --> 00:05:48,060 what interfaces will that structure implement? 114 00:05:48,060 --> 00:05:52,350 Will implement FnOnce, FnMut or Fn? 115 00:05:52,350 --> 00:05:57,210 And the answer is this closure will just implement FnOnce. 116 00:05:57,210 --> 00:05:59,100 It can only be called once. 117 00:05:59,100 --> 00:06:01,500 This closure can only be called once 118 00:06:01,500 --> 00:06:04,590 because it drops its external string. 119 00:06:04,590 --> 00:06:06,900 We looked at this in the previous section. 120 00:06:06,900 --> 00:06:09,030 A closure that captures variables 121 00:06:09,030 --> 00:06:11,520 by movement can only be called once. 122 00:06:11,520 --> 00:06:14,910 So when I pass this closure into the function, 123 00:06:14,910 --> 00:06:18,423 it's important that that closure only gets invoked once. 124 00:06:19,860 --> 00:06:23,070 Okay, so I can pass in an FnOnce parameter 125 00:06:23,070 --> 00:06:25,980 into here or anything which inherits from FnOnce. 126 00:06:25,980 --> 00:06:29,400 I can pass in a closure which implements FnMut 127 00:06:29,400 --> 00:06:31,530 and that's what I've done here. 128 00:06:31,530 --> 00:06:34,053 Okay, here I've called the function a second time, 129 00:06:35,100 --> 00:06:36,750 call that function again. 130 00:06:36,750 --> 00:06:40,020 And this time, that's the function. 131 00:06:40,020 --> 00:06:42,430 And this time, the closure I've passed in, 132 00:06:42,430 --> 00:06:44,030 now have a look at that closure. 133 00:06:45,090 --> 00:06:47,040 It'll be converted into a structure 134 00:06:47,040 --> 00:06:48,240 and that structure will implement 135 00:06:48,240 --> 00:06:51,690 either FnOnce or FnMut or Fn. 136 00:06:51,690 --> 00:06:54,690 The compiler will decide what trait it implements. 137 00:06:54,690 --> 00:06:56,190 If we look at it carefully, 138 00:06:56,190 --> 00:07:00,510 we can see that the structure, sorry, the closure mutates. 139 00:07:00,510 --> 00:07:03,693 It captures s2 and it mutates it. 140 00:07:04,980 --> 00:07:08,340 Therefore, this lambda, sorry, closure, 141 00:07:08,340 --> 00:07:10,050 keep on saying lambda, my mistake. 142 00:07:10,050 --> 00:07:12,120 This closure will be converted 143 00:07:12,120 --> 00:07:15,113 into a structure which implements FnMut. 144 00:07:16,589 --> 00:07:19,293 And because FnMut inherits from FnOnce, 145 00:07:20,730 --> 00:07:22,983 I can pass that closure into here. 146 00:07:23,880 --> 00:07:26,219 I can pass in anything which inherits from FnOnce, 147 00:07:26,219 --> 00:07:29,913 so FnOnce, FnMut or Fn. 148 00:07:30,990 --> 00:07:33,000 So this second call I can pass 149 00:07:33,000 --> 00:07:37,893 in a closure that will implement the FnMut trait. 150 00:07:39,210 --> 00:07:43,740 And then finally, my third call, this closure here, 151 00:07:43,740 --> 00:07:47,460 it captures s3, s3 is my string. 152 00:07:47,460 --> 00:07:50,700 It just prints the string, but it doesn't change it. 153 00:07:50,700 --> 00:07:55,700 So this closure will implement Fn, Fn inherits from FnOnce. 154 00:07:56,850 --> 00:08:00,090 So I can pass that closure in as a parameter in here. 155 00:08:00,090 --> 00:08:02,610 Remember, it was expecting a closure, 156 00:08:02,610 --> 00:08:05,340 which implemented FnOnce or anything 157 00:08:05,340 --> 00:08:06,690 which inherits from FnOnce. 158 00:08:08,220 --> 00:08:12,330 This closure implements Fn, that inherits from FnOnce, 159 00:08:12,330 --> 00:08:15,000 therefore, I can pass that closure in. 160 00:08:15,000 --> 00:08:18,390 So everything in here is gonna work fine. 161 00:08:18,390 --> 00:08:19,893 I'll just run it to confirm. 162 00:08:27,660 --> 00:08:29,206 All good. 163 00:08:29,206 --> 00:08:32,890 Okay, so I could pass in closure number one 164 00:08:34,264 --> 00:08:37,260 into FnOnce into my receive_fnonce function. 165 00:08:37,260 --> 00:08:39,780 I can then pass in the second closure, 166 00:08:39,780 --> 00:08:44,250 which changes string B to be bbb BBB. 167 00:08:44,250 --> 00:08:47,583 And then I can pass in a closure, which just implements Fn. 168 00:08:48,960 --> 00:08:52,530 Okay, so we've just seen a function, 169 00:08:52,530 --> 00:08:54,120 which receives a closure, 170 00:08:54,120 --> 00:08:57,063 which is bound to be of type FnOnce.