1 00:00:06,750 --> 00:00:10,470 - Rust has a standard structure type named iterator, 2 00:00:10,470 --> 00:00:14,130 which enables you to iterate over the items of a collection. 3 00:00:14,130 --> 00:00:17,910 You can specify an operation to perform on each element 4 00:00:17,910 --> 00:00:21,090 and you specify that operation as a closure. 5 00:00:21,090 --> 00:00:23,970 So in other words, you pass a closure into a method 6 00:00:23,970 --> 00:00:26,370 to say what operation to perform 7 00:00:26,370 --> 00:00:28,530 upon each element in a collection. 8 00:00:28,530 --> 00:00:30,390 So let's see some examples. 9 00:00:30,390 --> 00:00:31,650 Here's a simple example. 10 00:00:31,650 --> 00:00:35,250 I've got a vector of strings. 11 00:00:35,250 --> 00:00:37,800 Well, technically speaking, they're string slices, 12 00:00:37,800 --> 00:00:38,790 and they're ducks. 13 00:00:38,790 --> 00:00:41,160 Donald Duck and his nephews. 14 00:00:41,160 --> 00:00:46,160 And then here, v.iter returns an iterator object. 15 00:00:48,240 --> 00:00:51,750 And the iterator object has a for_each method. 16 00:00:51,750 --> 00:00:54,600 And the for_each method takes closure. 17 00:00:54,600 --> 00:00:58,110 And the closure specifies what to perform on each element. 18 00:00:58,110 --> 00:00:59,280 I'm sure you've seen this kind of code 19 00:00:59,280 --> 00:01:00,783 in other languages as well. 20 00:01:01,920 --> 00:01:05,640 So it knows that it's a vector of strings or string slices. 21 00:01:05,640 --> 00:01:07,500 Therefore, it knows that each element 22 00:01:07,500 --> 00:01:09,390 will be a string, effectively, 23 00:01:09,390 --> 00:01:12,600 and it'll print the string on the console. 24 00:01:12,600 --> 00:01:15,330 That's a nice simple example of using closures, 25 00:01:15,330 --> 00:01:19,710 passing the closure as a parameter into for_each. 26 00:01:19,710 --> 00:01:21,960 Okay, if you have a closure 27 00:01:21,960 --> 00:01:24,690 that doesn't actually make use of the parameter, 28 00:01:24,690 --> 00:01:26,850 then you can name the parameter underscore, 29 00:01:26,850 --> 00:01:29,160 and then you won't get a compiler called in. 30 00:01:29,160 --> 00:01:32,520 So in this example, here's my vector. 31 00:01:32,520 --> 00:01:36,360 I'm going to for_each string in my vector, 32 00:01:36,360 --> 00:01:38,580 I'm going to iterate. 33 00:01:38,580 --> 00:01:40,200 And instead of printing the duck name, 34 00:01:40,200 --> 00:01:43,380 it'll just print xxx, okay? 35 00:01:43,380 --> 00:01:47,790 So although, the for_each function will pass in 36 00:01:47,790 --> 00:01:51,360 a duckling as a parameter, I haven't actually used it. 37 00:01:51,360 --> 00:01:54,660 So I give it an underscore just to represent a parameter. 38 00:01:54,660 --> 00:01:58,290 I have to receive the parameter from for_each, 39 00:01:58,290 --> 00:01:59,550 but I'm not using it. 40 00:01:59,550 --> 00:02:02,670 So the underscore means I don't get a compiler warning 41 00:02:02,670 --> 00:02:04,203 about an unused variable. 42 00:02:05,160 --> 00:02:08,040 Going further, you can use the filter function 43 00:02:08,040 --> 00:02:09,690 and the map function. 44 00:02:09,690 --> 00:02:11,400 Have a look at this example here. 45 00:02:11,400 --> 00:02:14,670 It takes my vector of ducks and it iterates over them. 46 00:02:14,670 --> 00:02:17,670 The iter function returns an iterator. 47 00:02:17,670 --> 00:02:20,670 Upon the iterator, I call the filter function. 48 00:02:20,670 --> 00:02:23,310 Filter takes a closure 49 00:02:23,310 --> 00:02:25,380 that basically returns a true or false. 50 00:02:25,380 --> 00:02:27,030 It's a predicate. 51 00:02:27,030 --> 00:02:31,740 So this closure will be evaluated for each duck. 52 00:02:31,740 --> 00:02:34,110 And for each duck, for each element, 53 00:02:34,110 --> 00:02:37,920 if the element starts with a D, then retain that string. 54 00:02:37,920 --> 00:02:41,790 So donald and dewey will be retained. 55 00:02:41,790 --> 00:02:43,650 And for those which have been retained, 56 00:02:43,650 --> 00:02:44,820 they get transformed. 57 00:02:44,820 --> 00:02:47,040 The map function does a transformation. 58 00:02:47,040 --> 00:02:50,340 It takes in one of the elements, like donald or dewey, 59 00:02:50,340 --> 00:02:52,710 and it returns in uppercase. 60 00:02:52,710 --> 00:02:56,820 So it'd be capital Donald, capital Dewey. 61 00:02:56,820 --> 00:03:00,450 And whatever's left and whatever's been transformed, 62 00:03:00,450 --> 00:03:03,000 the filtered transformed elements 63 00:03:03,000 --> 00:03:05,850 will then be displayed on the console. 64 00:03:05,850 --> 00:03:07,620 So filter the elements you don't want 65 00:03:07,620 --> 00:03:10,650 or keep the elements you do want, transform them, 66 00:03:10,650 --> 00:03:12,420 and then display them. 67 00:03:12,420 --> 00:03:15,420 Bit like using Java 8 streams, 68 00:03:15,420 --> 00:03:17,523 if you've seen that in in Java. 69 00:03:18,450 --> 00:03:20,490 Right, if you want to, 70 00:03:20,490 --> 00:03:23,070 you can collect the results of an iteration 71 00:03:23,070 --> 00:03:26,430 back into some other container, like a vector. 72 00:03:26,430 --> 00:03:30,810 So in this example, I've taken my vector of strings, 73 00:03:30,810 --> 00:03:32,700 get back an iterator. 74 00:03:32,700 --> 00:03:36,150 Filter, only keep the ducks that end with a letter Y. 75 00:03:36,150 --> 00:03:40,380 Remember, the string has an ends_with method. 76 00:03:40,380 --> 00:03:45,210 It'll only keep huey and dewey because they end with a Y. 77 00:03:45,210 --> 00:03:47,850 It'll then transform them to uppercase, 78 00:03:47,850 --> 00:03:51,930 and then it collects those strings into a vector, okay? 79 00:03:51,930 --> 00:03:54,840 So the collect function is generic. 80 00:03:54,840 --> 00:03:56,220 When you call a collect function, 81 00:03:56,220 --> 00:03:59,730 you've gotta tell it what type of collection 82 00:03:59,730 --> 00:04:00,563 it's going to be. 83 00:04:00,563 --> 00:04:03,480 Is it going to be a vector or some other kind of collection? 84 00:04:03,480 --> 00:04:05,250 So we use that syntax. 85 00:04:05,250 --> 00:04:06,960 We'll have a look at generics in more detail 86 00:04:06,960 --> 00:04:07,980 later on in the course. 87 00:04:07,980 --> 00:04:11,190 But basically, the idea is when you call a generic method 88 00:04:11,190 --> 00:04:12,952 where you've gotta tell it the type name, 89 00:04:12,952 --> 00:04:14,910 you use this syntax, 90 00:04:14,910 --> 00:04:18,750 the name of the method, ::, and then the type parameter. 91 00:04:18,750 --> 00:04:23,430 A vector of string is the collection type of get back. 92 00:04:23,430 --> 00:04:25,710 Right, so that was actually quite straightforward. 93 00:04:25,710 --> 00:04:28,563 Let's have a look at these examples and we'll run them. 94 00:04:29,640 --> 00:04:33,555 Okay, so in main, I'll comment the last demo, 95 00:04:33,555 --> 00:04:35,760 demo_closures_iteration. 96 00:04:35,760 --> 00:04:38,250 One of the main reasons for using closures 97 00:04:38,250 --> 00:04:40,473 is when you iterate in over a collection. 98 00:04:41,640 --> 00:04:43,950 And then here's the code. 99 00:04:43,950 --> 00:04:46,020 So the functions that we looked at, 100 00:04:46,020 --> 00:04:48,750 I've just put into my demo, 101 00:04:48,750 --> 00:04:53,750 and I call those four functions from the top level. 102 00:04:53,970 --> 00:04:57,060 So let's run it and then look at the output, 103 00:04:57,060 --> 00:05:00,480 and just cast our minds over the code as we're doing so. 104 00:05:00,480 --> 00:05:01,473 Cargo run. 105 00:05:02,910 --> 00:05:07,910 Right then, so from the top, here are my ducks. 106 00:05:08,070 --> 00:05:10,533 All ducks, get the iterator object, 107 00:05:11,520 --> 00:05:15,189 invoke the for_each method on the iterator. 108 00:05:15,189 --> 00:05:16,800 For_each takes a closure. 109 00:05:16,800 --> 00:05:18,540 It'll call that closure four times 110 00:05:18,540 --> 00:05:21,300 with donald, huey, louie, and dewey. 111 00:05:21,300 --> 00:05:23,070 And it prints them. 112 00:05:23,070 --> 00:05:24,090 There we go. 113 00:05:24,090 --> 00:05:26,730 And then remember the example 114 00:05:26,730 --> 00:05:31,050 with an unused closure parameter. 115 00:05:31,050 --> 00:05:32,490 When I call for_each, 116 00:05:32,490 --> 00:05:36,210 it will pass a parameter into the closure, 117 00:05:36,210 --> 00:05:39,660 but we don't use it, we just print the xxx. 118 00:05:39,660 --> 00:05:42,390 So these are my redacted decks. 119 00:05:42,390 --> 00:05:44,370 They've been edited out. 120 00:05:44,370 --> 00:05:46,680 And then filter in and mapping, 121 00:05:46,680 --> 00:05:50,100 give me back uppercase ducks that start with a letter D. 122 00:05:50,100 --> 00:05:52,080 So give me back an iterator. 123 00:05:52,080 --> 00:05:54,870 Filter, keep the elements that start with a D, 124 00:05:54,870 --> 00:05:58,530 donald and dewey, then transform them to uppercase. 125 00:05:58,530 --> 00:06:01,380 And then for each one, display. 126 00:06:01,380 --> 00:06:04,830 Okay, so by uppercase D ducks are Donald and Dewey 127 00:06:04,830 --> 00:06:06,030 as advertised. 128 00:06:06,030 --> 00:06:11,030 And then finally, collect into some kind of variable, 129 00:06:11,880 --> 00:06:15,180 specifically into a vector of string, 130 00:06:15,180 --> 00:06:18,540 perform the iteration, get back an iterator. 131 00:06:18,540 --> 00:06:22,200 Filter, keep only the elements that end with a letter Y. 132 00:06:22,200 --> 00:06:24,873 So huey and dewey. 133 00:06:25,920 --> 00:06:27,540 Convert those type of case 134 00:06:27,540 --> 00:06:29,910 and then collect them back into a collection. 135 00:06:29,910 --> 00:06:32,070 I can then do another operation on later. 136 00:06:32,070 --> 00:06:34,860 So collect them into a vector of string. 137 00:06:34,860 --> 00:06:37,040 So this is gonna be a vector of string. 138 00:06:37,040 --> 00:06:40,230 A vector of string which I can then output. 139 00:06:40,230 --> 00:06:42,930 I can say, what's the length of my vector of string? 140 00:06:42,930 --> 00:06:46,380 There were two ducks that ended with a letter Y. 141 00:06:46,380 --> 00:06:49,620 And I can then iterate through my vector. 142 00:06:49,620 --> 00:06:50,453 That's my vector. 143 00:06:50,453 --> 00:06:52,710 Get an iterator object, 144 00:06:52,710 --> 00:06:55,500 and then call for_each to iterate like so. 145 00:06:55,500 --> 00:06:57,480 Okay, so that kind of is quite a nice way 146 00:06:57,480 --> 00:06:59,190 to round off the lesson really. 147 00:06:59,190 --> 00:07:02,400 Closures are really important in Rust 148 00:07:02,400 --> 00:07:05,250 for iterating over collections, for spawning threads, 149 00:07:05,250 --> 00:07:06,930 and for ad hoc usages as well. 150 00:07:06,930 --> 00:07:10,590 So we've looked at the syntax for using closures. 151 00:07:10,590 --> 00:07:12,090 We're going to revisit the topic again 152 00:07:12,090 --> 00:07:15,840 later on in the course when we look at generics and traits. 153 00:07:15,840 --> 00:07:17,730 But we'll actually look at how closures 154 00:07:17,730 --> 00:07:22,440 actually work internally in terms of objects and interfaces. 155 00:07:22,440 --> 00:07:24,603 Okay, but that's a good solid start.