1 00:00:00,000 --> 00:00:07,800 [No Audio] 2 00:00:07,801 --> 00:00:10,169 We will talk about Closures in this tutorial. 3 00:00:10,319 --> 00:00:12,719 So far, we have talked a lot about the 4 00:00:12,720 --> 00:00:15,239 functions and have used them quite a lot in 5 00:00:15,240 --> 00:00:17,609 our examples. One of the key property of the 6 00:00:17,610 --> 00:00:20,189 functions that we have used so far, was that, 7 00:00:20,190 --> 00:00:22,559 they were having names. Rust also allows us 8 00:00:22,560 --> 00:00:24,329 to create anonymous functions which are 9 00:00:24,330 --> 00:00:27,089 functions having no names. These no names or 10 00:00:27,090 --> 00:00:29,339 anonymous functions are called Closures by 11 00:00:29,340 --> 00:00:31,439 themselves. Closures aren't all that 12 00:00:31,440 --> 00:00:33,419 interesting, but when you combine them with 13 00:00:33,420 --> 00:00:36,269 functions, they takes closures as 14 00:00:36,270 --> 00:00:39,166 arguments, really powerful things are possible. 15 00:00:39,666 --> 00:00:41,099 I believe you would have already 16 00:00:41,100 --> 00:00:42,919 developed some excitement about closure, 17 00:00:42,920 --> 00:00:44,033 so let's get started. 18 00:00:45,329 --> 00:00:47,359 We will start with the basic syntax of closures. 19 00:00:47,360 --> 00:00:52,166 [No Audio] 20 00:00:52,167 --> 00:00:55,559 Any inputs to the closures are mentioned inside 21 00:00:55,560 --> 00:00:57,749 the two pipes or vertical bars followed by the 22 00:00:57,750 --> 00:00:59,999 body of the closure, which is represented 23 00:01:00,000 --> 00:01:02,459 using the two curly brackets. In case when 24 00:01:02,460 --> 00:01:04,589 the closure body only consists of a single 25 00:01:04,590 --> 00:01:06,749 statement, then we must keep adding the two 26 00:01:06,750 --> 00:01:10,079 curly brackets. Let's have a simple closure. 27 00:01:10,229 --> 00:01:11,705 I will declare a variable first. 28 00:01:11,706 --> 00:01:14,866 [No Audio] 29 00:01:14,867 --> 00:01:17,489 Next, I will define a closure with no inputs and having 30 00:01:17,490 --> 00:01:20,429 only a single line in its body. Since there 31 00:01:20,430 --> 00:01:22,619 are no inputs to this closure. So 32 00:01:22,620 --> 00:01:24,419 therefore, there is nothing between the two 33 00:01:24,420 --> 00:01:25,967 pipes, and the body will contain a 34 00:01:25,968 --> 00:01:27,266 single print statement. 35 00:01:27,267 --> 00:01:33,033 [No Audio] 36 00:01:33,034 --> 00:01:35,100 Since we have only a single statement in the 37 00:01:35,101 --> 00:01:36,900 body of the closure, therefore we are not 38 00:01:36,901 --> 00:01:38,640 required to enclose the statement in the 39 00:01:38,641 --> 00:01:41,610 curly brackets, we can assign a closure to 40 00:01:41,611 --> 00:01:44,010 some variable for instance, I will assign 41 00:01:44,011 --> 00:01:45,822 this closure to the variable of square. 42 00:01:45,823 --> 00:01:48,533 [No Audio] 43 00:01:48,534 --> 00:01:49,638 We can call this closure 44 00:01:49,639 --> 00:01:51,166 by writing the name of the variable. 45 00:01:51,167 --> 00:01:54,833 [No Audio] 46 00:01:54,834 --> 00:01:57,330 Okay before we proceed further, we 47 00:01:57,331 --> 00:01:59,866 should note a key point with regards to closures. 48 00:02:00,400 --> 00:02:01,800 The point is that, the closure 49 00:02:01,801 --> 00:02:04,860 captures its environment, this means that the 50 00:02:04,861 --> 00:02:06,780 closure will capture the variables from the 51 00:02:06,781 --> 00:02:09,600 code segment in which it is defined. In this 52 00:02:09,601 --> 00:02:11,790 case the variable x is known inside the 53 00:02:11,791 --> 00:02:14,700 closure body, this behavior is unlike functions. 54 00:02:15,666 --> 00:02:17,130 Inside the body of the function 55 00:02:17,131 --> 00:02:19,320 only those variables are known, which are 56 00:02:19,321 --> 00:02:21,900 defined inside the body or which are passed 57 00:02:21,901 --> 00:02:24,120 to the function as inputs. In this case, 58 00:02:24,150 --> 00:02:26,340 although we did not pass the variable of x to 59 00:02:26,341 --> 00:02:28,740 the closure, however, it is still known 60 00:02:28,741 --> 00:02:32,250 inside the body of the closure. In summary, 61 00:02:32,280 --> 00:02:34,140 all the variables in the code segment in 62 00:02:34,141 --> 00:02:36,433 which the closure is defined are visible to the closure. 63 00:02:37,766 --> 00:02:39,330 Let us now define a closure that 64 00:02:39,331 --> 00:02:42,858 accepts some inputs. First I will mention some inputs. 65 00:02:42,859 --> 00:02:47,100 [No Audio] 66 00:02:47,101 --> 00:02:48,150 You may note that, for the 67 00:02:48,151 --> 00:02:51,120 inputs, we need to mention the types as well, 68 00:02:51,121 --> 00:02:53,800 as well as the tape, just like the functions. 69 00:02:54,433 --> 00:02:56,100 I will update the print statement 70 00:02:56,101 --> 00:02:57,566 in the body of the closure also. 71 00:02:57,572 --> 00:03:01,866 [No Audio] 72 00:03:01,867 --> 00:03:04,200 I can now call this function by providing suitable 73 00:03:04,201 --> 00:03:07,400 inputs, I will call this with the input of x, 74 00:03:07,813 --> 00:03:09,088 let us execute. 75 00:03:09,089 --> 00:03:13,665 [No Audio] 76 00:03:13,666 --> 00:03:14,900 It is computing the square of 77 00:03:14,901 --> 00:03:17,940 the variable x just like functions. We can 78 00:03:17,970 --> 00:03:20,610 always call the square closure in subsequent 79 00:03:20,611 --> 00:03:23,610 code, I will define another variable y and 80 00:03:23,611 --> 00:03:25,560 then I will call the closure again by writing 81 00:03:25,561 --> 00:03:28,161 square but this time with the input of y. 82 00:03:28,162 --> 00:03:30,452 [No Audio] 83 00:03:30,453 --> 00:03:31,855 Let us execute again. 84 00:03:31,856 --> 00:03:34,933 [No Audio] 85 00:03:34,934 --> 00:03:36,600 That's great, it is computing the square. 86 00:03:36,791 --> 00:03:38,040 This means that, we can 87 00:03:38,041 --> 00:03:40,033 reuse the closure just like functions. 88 00:03:40,766 --> 00:03:43,050 Now, let us look at some interesting things about 89 00:03:43,051 --> 00:03:45,360 the closure. The first point to note is that 90 00:03:45,390 --> 00:03:47,640 redefining a variable with a different 91 00:03:47,641 --> 00:03:50,490 closure will use the new definition. Let us 92 00:03:50,491 --> 00:03:52,740 elaborate this further. To explain this, I 93 00:03:52,741 --> 00:03:55,470 will use the same program, instead of printing 94 00:03:55,471 --> 00:03:57,100 the square, I will print a cube. 95 00:03:57,503 --> 00:03:59,087 So I will update the print statement. 96 00:03:59,088 --> 00:04:02,820 [No Audio] 97 00:04:02,821 --> 00:04:04,539 This means now that, we have two 98 00:04:04,540 --> 00:04:06,300 different closures in the two lines. 99 00:04:07,100 --> 00:04:08,550 In fact, we have redefined the 100 00:04:08,551 --> 00:04:10,560 variable so that it corresponds to a 101 00:04:10,561 --> 00:04:13,290 different closure. Let us see which closure 102 00:04:13,291 --> 00:04:15,270 will be called by the call to square by 103 00:04:15,271 --> 00:04:16,410 executing this code. 104 00:04:16,423 --> 00:04:22,110 [No Audio] 105 00:04:22,111 --> 00:04:23,820 You may note that, in both the calls, the 106 00:04:23,821 --> 00:04:25,980 second definition is being called, and the 107 00:04:25,981 --> 00:04:28,133 code is displaying to us the cube of the value. 108 00:04:28,733 --> 00:04:30,570 The ownership rules in case of 109 00:04:30,571 --> 00:04:32,670 closures are applied in pretty much the same 110 00:04:32,671 --> 00:04:34,800 way is in connection with the functions. 111 00:04:35,466 --> 00:04:36,933 Let us look into the details. 112 00:04:38,100 --> 00:04:40,205 I will first define a closure which will display the 113 00:04:40,206 --> 00:04:43,182 general_info name and age that it will 114 00:04:43,183 --> 00:04:44,233 receive as an input. 115 00:04:44,239 --> 00:04:49,966 [No Audio] 116 00:04:49,980 --> 00:04:52,066 I will assign this closure to some variable. 117 00:04:52,067 --> 00:04:57,450 [No Audio] 118 00:04:57,451 --> 00:04:59,190 Next, I will define some variables whose 119 00:04:59,191 --> 00:05:00,930 values will be passed to the closure. 120 00:05:01,140 --> 00:05:02,925 First, I will define general_Info. 121 00:05:02,926 --> 00:05:05,266 [No Audio] 122 00:05:05,267 --> 00:05:06,896 Next, person_name, 123 00:05:06,897 --> 00:05:08,933 [No Audio] 124 00:05:08,934 --> 00:05:10,164 and finally the person_age. 125 00:05:10,165 --> 00:05:12,666 [No Audio] 126 00:05:12,667 --> 00:05:15,737 I will now call the closure with these variables. 127 00:05:15,738 --> 00:05:18,500 [No Audio] 128 00:05:18,501 --> 00:05:20,233 In this case now, the general_info 129 00:05:20,234 --> 00:05:21,600 variable ownership will be 130 00:05:21,601 --> 00:05:23,550 transferred to that of the variable inside 131 00:05:23,551 --> 00:05:26,200 the closure, while the variable a person_name 132 00:05:26,201 --> 00:05:27,510 ownership will remain with 133 00:05:27,511 --> 00:05:29,580 the variable of person_name and 134 00:05:29,581 --> 00:05:31,470 will not be transferred to the variable of 135 00:05:31,471 --> 00:05:35,100 name inside the closure. Lastly, the variable 136 00:05:35,101 --> 00:05:37,380 person_age ownership will also be 137 00:05:37,381 --> 00:05:39,690 transferred since it is being passed by value 138 00:05:39,691 --> 00:05:42,547 and not by reference. Let us execute the code. 139 00:05:42,548 --> 00:05:46,800 [No Audio] 140 00:05:46,801 --> 00:05:48,870 Now, if I add another print statement where I 141 00:05:48,871 --> 00:05:50,670 print the value for the variables which are 142 00:05:50,671 --> 00:05:53,130 being sent out by value after the closure is 143 00:05:53,131 --> 00:05:55,320 being called, so the Rust compiler will 144 00:05:55,321 --> 00:05:57,330 complain since the ownership of those 145 00:05:57,331 --> 00:05:59,520 variables have been transferred, let me 146 00:05:59,550 --> 00:06:00,679 include a print statement. 147 00:06:00,680 --> 00:06:07,350 [No Audio] 148 00:06:07,351 --> 00:06:09,270 You may note that, the compiler is not happy 149 00:06:09,271 --> 00:06:12,570 saying that borrow of a moved value. Okay. 150 00:06:12,571 --> 00:06:14,370 You may however, note that if I change the 151 00:06:14,371 --> 00:06:16,320 variable to date of person_name, 152 00:06:16,321 --> 00:06:17,604 there won't be any issues. 153 00:06:17,605 --> 00:06:22,469 [No Audio] 154 00:06:22,470 --> 00:06:23,190 This is because, in 155 00:06:23,191 --> 00:06:25,230 this case the variable ownership was not been 156 00:06:25,231 --> 00:06:27,870 transferred, as we have used a reference to 157 00:06:27,871 --> 00:06:30,300 this variable. In summary, we have to pay 158 00:06:30,330 --> 00:06:32,130 attention to the ownership rules when we are 159 00:06:32,131 --> 00:06:35,430 passing values to the closure. Okay, let us 160 00:06:35,431 --> 00:06:37,710 move to the next point. The closures are able 161 00:06:37,711 --> 00:06:40,410 to infer the outputs and inputs themselves 162 00:06:40,440 --> 00:06:42,510 and it is unlike functions where we have to 163 00:06:42,511 --> 00:06:44,700 explicitly mention and set up the inputs and 164 00:06:44,701 --> 00:06:47,266 output types. Let us elaborate this in detail. 165 00:06:48,066 --> 00:06:49,650 I will start with a simple closure 166 00:06:49,651 --> 00:06:51,255 for computing the square of a number. 167 00:06:51,256 --> 00:06:58,980 [No Audio] 168 00:06:58,981 --> 00:07:00,870 You may note that, currently the input and 169 00:07:00,900 --> 00:07:03,150 output types are unknown for the closure. 170 00:07:03,450 --> 00:07:05,310 Next I will define a variable x and we'll 171 00:07:05,311 --> 00:07:07,471 call this closure with the variable x. 172 00:07:07,472 --> 00:07:12,540 [No Audio] 173 00:07:12,541 --> 00:07:14,460 You may note that as soon as I call the 174 00:07:14,461 --> 00:07:16,900 closure, the type will be updated for the inputs. 175 00:07:16,901 --> 00:07:19,200 Now once the inputs are being set and 176 00:07:19,201 --> 00:07:21,300 inferred by the Rust based on the first call 177 00:07:21,301 --> 00:07:23,533 to the closure, they will be kind of locked. 178 00:07:24,033 --> 00:07:25,710 If we call the same closure with 179 00:07:25,711 --> 00:07:27,930 different types of inputs the Rust compiler 180 00:07:27,931 --> 00:07:30,690 will complain. For instance, if I declare 181 00:07:30,720 --> 00:07:33,000 another variable of y having a float value, 182 00:07:33,030 --> 00:07:34,825 and we'll use it to call the closure. 183 00:07:34,826 --> 00:07:39,433 [No Audio] 184 00:07:39,434 --> 00:07:42,180 You may note that, the compiler is not happy. This is 185 00:07:42,181 --> 00:07:44,730 because the first call to the closure sets up 186 00:07:44,731 --> 00:07:46,860 the inputs and output types and the Rust 187 00:07:46,861 --> 00:07:49,110 assumes that subsequent calls to the same 188 00:07:49,111 --> 00:07:51,866 closure will use the same input same output types. 189 00:07:52,633 --> 00:07:54,833 If I comment out the first call, 190 00:07:55,800 --> 00:07:58,140 you may note now, that the inputs are being 191 00:07:58,170 --> 00:08:01,710 updated accordingly. Okay, now, let us move 192 00:08:01,711 --> 00:08:04,110 to the next topic, we can also pass the 193 00:08:04,111 --> 00:08:06,000 closure to a function as a parameter. 194 00:08:07,266 --> 00:08:09,420 In this program, we will write a function which will 195 00:08:09,421 --> 00:08:11,533 be used to compute the division of two numbers. 196 00:08:12,033 --> 00:08:14,370 Moreover, the same function 197 00:08:14,371 --> 00:08:15,810 will use a closure to check if the 198 00:08:15,811 --> 00:08:18,720 denominator of the fraction passed to the 199 00:08:18,721 --> 00:08:22,110 function is zero or not. So, let us start to 200 00:08:22,111 --> 00:08:25,333 code this program, I will first define a closure. 201 00:08:25,966 --> 00:08:27,630 The closure inputs will be a float 202 00:08:27,631 --> 00:08:30,450 number and it will return a bool value, which 203 00:08:30,480 --> 00:08:32,789 is true when the number representing the 204 00:08:32,820 --> 00:08:35,640 denominator is not zero and false otherwise, 205 00:08:35,760 --> 00:08:37,066 let me add the code. 206 00:08:37,067 --> 00:08:41,727 [No Audio] 207 00:08:41,728 --> 00:08:43,799 Okay, next I will define 208 00:08:43,800 --> 00:08:45,780 the function of division with three inputs. 209 00:08:46,350 --> 00:08:48,420 The first two inputs will be numbers and the 210 00:08:48,421 --> 00:08:51,030 third input will be a closure, which will be 211 00:08:51,060 --> 00:08:52,900 representing using generics. 212 00:08:53,854 --> 00:08:55,166 Let us set up the inputs. 213 00:08:55,196 --> 00:09:00,779 [No Audio] 214 00:09:00,780 --> 00:09:02,789 We will also need to mention the same generic 215 00:09:02,790 --> 00:09:05,129 just after the name of the function, I will 216 00:09:05,130 --> 00:09:07,349 set its type to that of a function with the 217 00:09:07,350 --> 00:09:09,718 input of f32 and the output of bool. 218 00:09:09,719 --> 00:09:12,866 [No Audio] 219 00:09:12,867 --> 00:09:16,259 This tells the Rust that we are using f as a 220 00:09:16,260 --> 00:09:18,329 generic but it's type will be a function, 221 00:09:18,330 --> 00:09:20,759 which will accept an i32 as an input and 222 00:09:20,760 --> 00:09:22,266 will return a bool value. 223 00:09:22,966 --> 00:09:24,179 Inside the function 224 00:09:24,180 --> 00:09:25,829 I will first make a call to the closure to 225 00:09:25,830 --> 00:09:28,499 check if the denominator is zero or not. In 226 00:09:28,500 --> 00:09:30,629 case it is 0 I will print it the division 227 00:09:30,630 --> 00:09:33,719 is not possible and in case it is not 0, I 228 00:09:33,720 --> 00:09:35,733 will print to the user the result of division. 229 00:09:35,734 --> 00:09:36,961 So let me add the code. 230 00:09:36,962 --> 00:09:45,419 [No Audio] 231 00:09:45,420 --> 00:09:47,819 Let us use this function now. I will call it 232 00:09:47,820 --> 00:09:50,489 with the input 5 and 10 and the third 233 00:09:50,490 --> 00:09:52,799 input will be the variable which we can use 234 00:09:52,800 --> 00:09:55,049 for calling the closure which in this case is 235 00:09:55,050 --> 00:09:56,215 the variable of division. 236 00:09:56,216 --> 00:10:02,309 [No Audio] 237 00:10:02,310 --> 00:10:04,679 Inside the body of the function the statement 238 00:10:04,680 --> 00:10:08,639 of f of y means that we are calling the 239 00:10:08,640 --> 00:10:11,729 closure division_status. In other 240 00:10:11,730 --> 00:10:13,979 words, the f of y has the same meaning as 241 00:10:13,980 --> 00:10:15,899 that of division_status with the 242 00:10:15,900 --> 00:10:17,200 variable y as input. 243 00:10:17,856 --> 00:10:19,109 Okay, let me call it one 244 00:10:19,110 --> 00:10:21,599 more time with a second parameter as that of 245 00:10:21,600 --> 00:10:25,230 0 or the denominators is set to the value of 0. 246 00:10:25,231 --> 00:10:29,066 [No Audio] 247 00:10:29,067 --> 00:10:30,845 Let us cargo run this to check the result. 248 00:10:30,846 --> 00:10:34,000 [No Audio] 249 00:10:34,001 --> 00:10:36,029 For the first call, the result is the 250 00:10:36,030 --> 00:10:38,069 division have the two numbers, while for the 251 00:10:38,070 --> 00:10:40,589 second call the result is the print message 252 00:10:40,590 --> 00:10:43,799 that the division is not possible. Okay, that 253 00:10:43,800 --> 00:10:45,779 brings us to the end of this tutorial, we 254 00:10:45,780 --> 00:10:47,699 have learned about the closures and how to 255 00:10:47,700 --> 00:10:49,919 use them in different ways. In the upcoming 256 00:10:49,920 --> 00:10:51,419 tutorial, we will be covering more 257 00:10:51,420 --> 00:10:53,789 interesting concepts about the closures and 258 00:10:53,790 --> 00:10:56,189 its capturing environment. So do come back to 259 00:10:56,190 --> 00:10:57,302 cover that event and then 260 00:10:57,303 --> 00:10:58,668 happy Rust programming. 261 00:10:58,669 --> 00:11:03,633 [No Audio]