1 00:00:06,630 --> 00:00:07,463 - In this section, 2 00:00:07,463 --> 00:00:09,720 we are going to talk about how to pass references 3 00:00:09,720 --> 00:00:11,280 into a function. 4 00:00:11,280 --> 00:00:13,860 First of all, a quick recap of what we've seen already, 5 00:00:13,860 --> 00:00:15,660 passing by value. 6 00:00:15,660 --> 00:00:18,660 In this example here, I've got some function. 7 00:00:18,660 --> 00:00:21,693 It takes an i32 by value. 8 00:00:23,370 --> 00:00:26,460 When we pass in an integer 32, 9 00:00:26,460 --> 00:00:31,460 a bit copy occurs because i32 implements the copy trait. 10 00:00:31,740 --> 00:00:32,573 So that's good. 11 00:00:33,840 --> 00:00:38,580 The function also receives a string by value 12 00:00:38,580 --> 00:00:40,590 and that's a little bit more problematic 13 00:00:40,590 --> 00:00:43,023 because string doesn't implement the copy trait. 14 00:00:44,070 --> 00:00:49,070 So if I have a string up here, s and I pass it in, 15 00:00:49,530 --> 00:00:53,670 I move ownership from s into sparam. 16 00:00:53,670 --> 00:00:58,020 So this variable up here loses ownership of the text. 17 00:00:58,020 --> 00:01:01,380 It donates ownership to the function. 18 00:01:01,380 --> 00:01:03,480 Sparam goes at a scope, 19 00:01:03,480 --> 00:01:07,470 the end of the function, the contents of sparam disappears 20 00:01:07,470 --> 00:01:10,380 and then when we come back up to our original function, 21 00:01:10,380 --> 00:01:12,750 we can't use s anymore. 22 00:01:12,750 --> 00:01:17,160 So pass in non-copy types by value, probably not a good idea 23 00:01:17,160 --> 00:01:18,960 because you lose the object 24 00:01:18,960 --> 00:01:21,840 as soon as you pass it into the function. 25 00:01:21,840 --> 00:01:23,400 Okay, so here we go. 26 00:01:23,400 --> 00:01:26,460 For copy types like i32 27 00:01:26,460 --> 00:01:29,580 the value is bit copied into the parameter. 28 00:01:29,580 --> 00:01:32,847 As discussed, the caller retains ownership of n 29 00:01:32,847 --> 00:01:34,983 and can use n afterwards. 30 00:01:36,780 --> 00:01:41,780 For non-copy types, like string, the value is moved 31 00:01:42,210 --> 00:01:45,513 from the original string variable into this one. 32 00:01:46,710 --> 00:01:49,920 You lose ownership of the string up here, 33 00:01:49,920 --> 00:01:52,560 you donate it or you move ownership to here. 34 00:01:52,560 --> 00:01:54,540 But of course, because it's a local variable, 35 00:01:54,540 --> 00:01:58,560 then sparam goes at a scope and the string is dropped. 36 00:01:58,560 --> 00:02:01,350 That's why you can't then use it. 37 00:02:01,350 --> 00:02:04,023 When you come back the object has disappeared. 38 00:02:05,070 --> 00:02:06,720 So in situations like this, 39 00:02:06,720 --> 00:02:11,400 rather than passing copy or non-copy types by value, 40 00:02:11,400 --> 00:02:13,530 you could, and should, consider passing them 41 00:02:13,530 --> 00:02:15,720 by reference instead. 42 00:02:15,720 --> 00:02:18,660 So the called function, the function that you're calling, 43 00:02:18,660 --> 00:02:20,563 receives a reference to the object. 44 00:02:20,563 --> 00:02:24,210 It borrows the object, but it doesn't own it. 45 00:02:24,210 --> 00:02:27,780 The original call in function retains ownership. 46 00:02:27,780 --> 00:02:31,170 Okay, so after the called function returns back to you, 47 00:02:31,170 --> 00:02:33,570 you can still use the value afterwards. 48 00:02:33,570 --> 00:02:37,050 You didn't pass ownership into the other function. 49 00:02:37,050 --> 00:02:40,470 You just allowed the other function to borrow your value. 50 00:02:40,470 --> 00:02:42,090 A reference in other words. 51 00:02:42,090 --> 00:02:44,340 But the original function retains ownership. 52 00:02:44,340 --> 00:02:47,340 This is the main way to pass objects, 53 00:02:47,340 --> 00:02:51,000 non-copy objects into functions. 54 00:02:51,000 --> 00:02:52,260 So how do you do it? 55 00:02:52,260 --> 00:02:55,590 How do you pass a reference parameter into a function? 56 00:02:55,590 --> 00:02:58,980 Well, you just put an ampersand in front of the object 57 00:02:58,980 --> 00:03:01,380 to give you a reference. 58 00:03:01,380 --> 00:03:05,130 Here is an example, here's my call in function. 59 00:03:05,130 --> 00:03:07,890 I've declared a string variable called s, oh, 60 00:03:07,890 --> 00:03:09,633 and an integer called n. 61 00:03:10,680 --> 00:03:15,540 I pass a reference to the integer into some function 62 00:03:15,540 --> 00:03:19,860 and I pass a reference to the string into some function. 63 00:03:19,860 --> 00:03:24,300 Technically the function borrows n and it borrows s, okay? 64 00:03:24,300 --> 00:03:28,740 But the called function doesn't own the values. 65 00:03:28,740 --> 00:03:31,080 When that called function returns, 66 00:03:31,080 --> 00:03:35,220 the original function still owns n and s, okay? 67 00:03:35,220 --> 00:03:40,220 So the called function borrowed n and borrowed s, 68 00:03:40,350 --> 00:03:42,240 it had references to them, 69 00:03:42,240 --> 00:03:45,480 but ownership remained with the original function. 70 00:03:45,480 --> 00:03:48,630 So I can still continue to use, well, specifically, 71 00:03:48,630 --> 00:03:51,300 I can still continue to use s afterwards 72 00:03:51,300 --> 00:03:53,010 because I haven't lost ownership. 73 00:03:53,010 --> 00:03:57,540 So pass in by reference is a key thing to do 74 00:03:57,540 --> 00:04:00,180 when you've got non-copy objects. 75 00:04:00,180 --> 00:04:04,110 So if I pass a reference parameter into a function, 76 00:04:04,110 --> 00:04:07,470 how can I then use a reference parameter in a function? 77 00:04:07,470 --> 00:04:08,880 Well, I'm glad you asked. 78 00:04:08,880 --> 00:04:11,040 In order to use a reference parameter, 79 00:04:11,040 --> 00:04:13,740 you've gotta use a star to dereference it. 80 00:04:13,740 --> 00:04:16,200 So as a C developer or C++, 81 00:04:16,200 --> 00:04:18,720 you might think of this as being more like pointers 82 00:04:18,720 --> 00:04:20,190 than like references. 83 00:04:20,190 --> 00:04:24,060 The syntax is more like pointers than it is like references. 84 00:04:24,060 --> 00:04:25,530 So here's an example. 85 00:04:25,530 --> 00:04:28,240 The function receives a reference 86 00:04:29,190 --> 00:04:33,120 or borrows some kind of i32 87 00:04:33,120 --> 00:04:38,120 and it borrows some kind of string, like so, okay? 88 00:04:38,460 --> 00:04:43,050 So we're basically referring to an external integer 89 00:04:43,050 --> 00:04:46,440 and we're referring to an external string. 90 00:04:46,440 --> 00:04:49,650 So in order to dereference and get the values, 91 00:04:49,650 --> 00:04:51,750 we use the star, okay? 92 00:04:51,750 --> 00:04:56,220 So take my iparam reference 93 00:04:56,220 --> 00:04:59,520 and give me the contents of what it refers to. 94 00:04:59,520 --> 00:05:01,620 The star will give me the contents, 95 00:05:01,620 --> 00:05:04,680 the integer, that it refers to. 96 00:05:04,680 --> 00:05:07,007 I wanna say star sparam. 97 00:05:07,950 --> 00:05:10,380 Sparam is a reference to the string, 98 00:05:10,380 --> 00:05:13,320 star sparam is the contents of that string. 99 00:05:13,320 --> 00:05:15,300 It's a string object. 100 00:05:15,300 --> 00:05:16,770 And then upon the string object, 101 00:05:16,770 --> 00:05:18,870 I can invoke a method to uppercase. 102 00:05:18,870 --> 00:05:23,100 So it would kind of uppercase the contents of the string, 103 00:05:23,100 --> 00:05:25,080 the text, like so. 104 00:05:25,080 --> 00:05:29,520 So it is mixed syntax, it must say, for me, 105 00:05:29,520 --> 00:05:33,150 my original background in this kind of thing was in C++ 106 00:05:33,150 --> 00:05:35,910 and this is kind of like a hybrid syntax. 107 00:05:35,910 --> 00:05:40,023 It's different from C++ and you have to recognize that. 108 00:05:41,100 --> 00:05:45,390 So a reference, you declare it as a reference here, 109 00:05:45,390 --> 00:05:48,090 but really it behaves more like a pointer 110 00:05:48,090 --> 00:05:50,610 in the sense that you dereference it 111 00:05:50,610 --> 00:05:53,310 to get back to the object that you first thought of. 112 00:05:53,310 --> 00:05:56,640 And by the way, if you're a C++ developer 113 00:05:56,640 --> 00:05:58,650 and you're wondering if you could rewrite this 114 00:05:58,650 --> 00:06:03,650 as sparam, arrow to uppercase, 115 00:06:04,650 --> 00:06:07,800 you can't, there's no arrow in rust. 116 00:06:07,800 --> 00:06:10,533 You'd have to use the star and the parentheses. 117 00:06:12,270 --> 00:06:15,840 Now, luckily for us, or maybe not, 118 00:06:15,840 --> 00:06:20,310 if you have a reference to an object 119 00:06:20,310 --> 00:06:23,670 and you want to invoke a method on the object, 120 00:06:23,670 --> 00:06:27,273 rust does actually allow you to invoke the method directly. 121 00:06:28,950 --> 00:06:31,710 Okay, so instead of writing it with the star 122 00:06:31,710 --> 00:06:34,833 and the parentheses, you could just write it like so. 123 00:06:35,970 --> 00:06:39,510 It's quite clever the way that rust works internally, 124 00:06:39,510 --> 00:06:40,930 if you have an object 125 00:06:41,850 --> 00:06:44,973 and you want to invoke a method, you can say object.method. 126 00:06:46,080 --> 00:06:50,760 If you have a reference, then you can say reference.method. 127 00:06:50,760 --> 00:06:52,350 It kind of looks at the syntax, 128 00:06:52,350 --> 00:06:53,970 understands what you're trying to do 129 00:06:53,970 --> 00:06:55,770 and treats them interchangeably. 130 00:06:55,770 --> 00:07:00,770 So you don't have to explicitly dereference it like so 131 00:07:01,530 --> 00:07:03,360 and rust developers don't. 132 00:07:03,360 --> 00:07:05,670 Okay, they benefit from the syntax 133 00:07:05,670 --> 00:07:08,760 and the fact that it allows you to invoke a method 134 00:07:08,760 --> 00:07:10,080 using an object 135 00:07:10,080 --> 00:07:13,203 or using a reference using the same syntax. 136 00:07:14,550 --> 00:07:16,560 Well, I've almost finished what I wanted to say 137 00:07:16,560 --> 00:07:17,610 in this section, 138 00:07:17,610 --> 00:07:20,950 but I wanna say just a few more words about strings 139 00:07:21,840 --> 00:07:24,780 because strings are kind of a bit tricky 140 00:07:24,780 --> 00:07:26,400 because there are two different ways 141 00:07:26,400 --> 00:07:27,930 to represent the string. 142 00:07:27,930 --> 00:07:30,540 You can have an ampersand string, 143 00:07:30,540 --> 00:07:33,740 a reference to a string object, okay? 144 00:07:33,740 --> 00:07:36,390 So if you have a function that takes a reference 145 00:07:36,390 --> 00:07:39,840 to a string, you must pass in an actual reference 146 00:07:39,840 --> 00:07:41,880 to an actual string object. 147 00:07:41,880 --> 00:07:45,600 You can't pass in a string slice, right? 148 00:07:45,600 --> 00:07:48,330 So have a look at this piece of code here. 149 00:07:48,330 --> 00:07:52,080 I've got a function that takes a string reference. 150 00:07:52,080 --> 00:07:56,220 We must give it a reference to an actual string object. 151 00:07:56,220 --> 00:07:58,953 We're not allowed to give it a string slice. 152 00:07:59,820 --> 00:08:01,920 Okay, so in my call, up here, 153 00:08:01,920 --> 00:08:06,600 in my main code up here, s is a string object 154 00:08:06,600 --> 00:08:11,600 which points to, 'hello,' like so, so, so good. 155 00:08:13,740 --> 00:08:17,370 I can pass, I can take a reference to s 156 00:08:17,370 --> 00:08:19,290 and pass that into the function. 157 00:08:19,290 --> 00:08:23,100 So that will indeed be a string reference. 158 00:08:23,100 --> 00:08:24,690 That's fine. 159 00:08:24,690 --> 00:08:27,540 Sparam will effectively be a reference 160 00:08:27,540 --> 00:08:30,843 to the string object like so, and that's fine, 161 00:08:31,770 --> 00:08:36,660 but I can't pass in a string literal, okay? 162 00:08:36,660 --> 00:08:39,930 Because remember, a string literal is just, literally, 163 00:08:39,930 --> 00:08:42,783 a piece of text like that. 164 00:08:43,800 --> 00:08:48,090 It's just a slice of text, and that doesn't work. 165 00:08:48,090 --> 00:08:51,690 If the function was expecting a string reference, 166 00:08:51,690 --> 00:08:54,843 it really is expecting a reference to an actual string. 167 00:08:55,920 --> 00:09:00,120 You can't give it a reference to a slice, okay? 168 00:09:00,120 --> 00:09:02,040 Because that's a different beastie. 169 00:09:02,040 --> 00:09:06,797 So that's not so great, really, is it? 170 00:09:08,040 --> 00:09:11,820 If you declare a function that takes a string reference, 171 00:09:11,820 --> 00:09:14,823 you've gotta actually give it an actual string object. 172 00:09:17,580 --> 00:09:20,467 You can't pass in just a string literal, so. 173 00:09:23,070 --> 00:09:25,080 Well there's a solution at hand. 174 00:09:25,080 --> 00:09:27,660 What you do is you actually declare the function 175 00:09:27,660 --> 00:09:31,500 to take a str reference, okay? 176 00:09:31,500 --> 00:09:35,013 So not a string reference, but a str reference. 177 00:09:36,270 --> 00:09:39,870 So a str reference can actually, 178 00:09:39,870 --> 00:09:43,470 you can pass in an ampersand string. 179 00:09:43,470 --> 00:09:46,230 You can take a reference to an actual string object 180 00:09:46,230 --> 00:09:49,440 and assign it into an ampersand str. 181 00:09:49,440 --> 00:09:51,960 To use the terminology in rust, 182 00:09:51,960 --> 00:09:56,960 a string reference decays or can be converted 183 00:09:57,360 --> 00:09:59,910 into a str reference. 184 00:09:59,910 --> 00:10:01,980 So to put it another way, 185 00:10:01,980 --> 00:10:04,980 a string slice can either refer to an actual string 186 00:10:04,980 --> 00:10:06,690 or a string literal. 187 00:10:06,690 --> 00:10:11,520 You can pass in either a string reference or a string slice. 188 00:10:11,520 --> 00:10:13,470 So this function here takes, 189 00:10:13,470 --> 00:10:15,330 and this would be the best way to do it, 190 00:10:15,330 --> 00:10:18,120 this function takes a string slice. 191 00:10:18,120 --> 00:10:22,740 Either an existing string or a string literal. 192 00:10:22,740 --> 00:10:24,840 So let me work through this example. 193 00:10:24,840 --> 00:10:27,930 I'm gonna show you some code to illustrate all this 194 00:10:27,930 --> 00:10:28,763 in a minute. 195 00:10:28,763 --> 00:10:32,070 So from the top, s is an actual string object, 196 00:10:32,070 --> 00:10:34,620 an actual string object, which holds some text, 197 00:10:34,620 --> 00:10:39,090 'hello,' like so, and according to the rules, 198 00:10:39,090 --> 00:10:40,533 and it is just a rule, 199 00:10:43,507 --> 00:10:48,507 if I take ampersand s then that type is string reference. 200 00:10:48,630 --> 00:10:52,833 You are allowed to pass a string reference into a slice. 201 00:10:53,910 --> 00:10:56,580 Okay, so sparam, what actually happens is 202 00:10:56,580 --> 00:11:01,580 sparam ends up being a reference to the text, like that. 203 00:11:02,250 --> 00:11:05,220 The actual text, and plus the length. 204 00:11:05,220 --> 00:11:09,180 Remember that string slices are fat pointers. 205 00:11:09,180 --> 00:11:12,930 They have a pointer and they have the length as well. 206 00:11:12,930 --> 00:11:16,800 So if you passed in an actual string object as a reference 207 00:11:16,800 --> 00:11:21,060 then you will be referring to the text 208 00:11:21,060 --> 00:11:24,963 that the string contains, like so, that is allowed. 209 00:11:26,460 --> 00:11:30,390 On the other hand, if you just pass in literal text, 210 00:11:30,390 --> 00:11:34,770 like 'Joe,' like that, then in that case, 211 00:11:34,770 --> 00:11:38,130 sparam would be a reference into that slice. 212 00:11:38,130 --> 00:11:40,200 So it either be a reference to that slice 213 00:11:40,200 --> 00:11:43,530 or it would've been a reference into that piece of text 214 00:11:43,530 --> 00:11:44,460 inside the string. 215 00:11:44,460 --> 00:11:49,460 So, long story short, if you wanna pass text around 216 00:11:49,500 --> 00:11:53,010 the preferred way to do it is to pass it as a string slice. 217 00:11:53,010 --> 00:11:55,680 That means you can pass in an actual string object 218 00:11:55,680 --> 00:11:57,150 by reference 219 00:11:57,150 --> 00:12:01,410 and you can pass in just a string literal as well. 220 00:12:01,410 --> 00:12:04,080 That's the preferred way to pass strings 221 00:12:04,080 --> 00:12:05,673 by reference into a function. 222 00:12:06,810 --> 00:12:07,950 Right, one other thing, 223 00:12:07,950 --> 00:12:10,290 and then we'll have a look at the example. 224 00:12:10,290 --> 00:12:12,990 If you have a reference parameter 225 00:12:12,990 --> 00:12:17,430 then the default formatter, when you print a reference 226 00:12:17,430 --> 00:12:19,860 it actually displays the value. 227 00:12:19,860 --> 00:12:24,300 It automatically does a star to give you the value 228 00:12:24,300 --> 00:12:25,803 that the reference refers to. 229 00:12:27,360 --> 00:12:29,580 If you want to get back the actual address 230 00:12:29,580 --> 00:12:31,080 that the reference refers to 231 00:12:31,080 --> 00:12:35,670 then you can use the p formatter, the pointer formatter. 232 00:12:35,670 --> 00:12:40,670 Okay, so let's have a look at that. 233 00:12:42,180 --> 00:12:46,230 I've got a reference to an integer 234 00:12:46,230 --> 00:12:50,280 and I've got a string slice, basically. 235 00:12:50,280 --> 00:12:53,280 If I just pass my reference, 236 00:12:53,280 --> 00:12:56,760 the default formatter will print the value of the integer 237 00:12:56,760 --> 00:12:59,640 and it'll print the value of the string. 238 00:12:59,640 --> 00:13:01,560 Or to put it another way, 239 00:13:01,560 --> 00:13:03,810 the default formatter, kind of, 240 00:13:03,810 --> 00:13:06,480 automatically on your behalf, 241 00:13:06,480 --> 00:13:10,620 it automatically dereferences to give you back the contents 242 00:13:10,620 --> 00:13:13,353 of the integer and the contents of the string. 243 00:13:14,400 --> 00:13:17,610 Okay, if you wanted to get back the actual addresses 244 00:13:17,610 --> 00:13:19,383 then you just say :p. 245 00:13:20,400 --> 00:13:24,120 take the reference and print it using the pointer formatter, 246 00:13:24,120 --> 00:13:27,000 take the string and print it using the pointer format. 247 00:13:27,000 --> 00:13:29,700 That'll give you the address that the reference refers to. 248 00:13:29,700 --> 00:13:32,190 So references really are pointers, 249 00:13:32,190 --> 00:13:34,710 addresses under the covers, 250 00:13:34,710 --> 00:13:37,800 but you can output them as actual values 251 00:13:37,800 --> 00:13:39,243 using the default formatter.