1 00:00:00,420 --> 00:00:01,730 Welcome to module 4 2 00:00:02,240 --> 00:00:03,390 on returning Result 3 00:00:03,590 --> 00:00:04,740 and using ?. 4 00:00:06,550 --> 00:00:08,529 In this module, we're going to cover 5 00:00:08,729 --> 00:00:10,449 how to return Result values from 6 00:00:10,649 --> 00:00:11,860 your own functions that might fail. 7 00:00:12,370 --> 00:00:14,469 Then, we'll discuss how to use the ? 8 00:00:14,669 --> 00:00:16,328 operator within functions that return 9 00:00:16,528 --> 00:00:18,159 Result to propagate errors in 10 00:00:18,359 --> 00:00:19,000 a concise way. 11 00:00:19,540 --> 00:00:21,639 Understanding what the ? operator 12 00:00:21,839 --> 00:00:23,589 does will help you to understand where 13 00:00:23,789 --> 00:00:24,910 you can and can't use it. 14 00:00:25,420 --> 00:00:26,760 And we'll round out the module 15 00:00:26,960 --> 00:00:28,820 with some recent features added to Rust 16 00:00:29,120 --> 00:00:31,030 and make the ? operator useful 17 00:00:31,230 --> 00:00:32,180 in more contexts. 18 00:00:33,850 --> 00:00:35,800 Let's start with how to return a Result. 19 00:00:37,430 --> 00:00:39,510 Imagine we're implementing the back end 20 00:00:39,710 --> 00:00:41,729 of a Twitter-like website where people 21 00:00:41,929 --> 00:00:43,619 can post statuses containing up to 22 00:00:43,819 --> 00:00:45,330 200 bytes of text each. 23 00:00:46,850 --> 00:00:48,919 If a user of our site tries 24 00:00:49,119 --> 00:00:50,929 to send a status containing more 25 00:00:51,129 --> 00:00:52,490 than 200 bytes of text, 26 00:00:52,910 --> 00:00:54,230 we should return an error. 27 00:00:55,930 --> 00:00:57,700 We're going to write the part of this web app 28 00:00:57,900 --> 00:00:59,830 that's the function named save_status. 29 00:01:00,870 --> 00:01:03,210 This function takes the content of a status, 30 00:01:03,510 --> 00:01:05,440 checks that there are fewer than 200 bytes of 31 00:01:05,640 --> 00:01:07,650 text, and saves it to the database. 32 00:01:08,640 --> 00:01:10,260 If those operations succeed, 33 00:01:10,560 --> 00:01:12,809 we'll return the ID of the new status' 34 00:01:13,009 --> 00:01:13,820 database record. 35 00:01:14,370 --> 00:01:16,020 If those operations fail, 36 00:01:16,350 --> 00:01:18,209 we'll return an error describing what went 37 00:01:18,409 --> 00:01:18,570 wrong. 38 00:01:20,130 --> 00:01:22,080 The save_status function signature 39 00:01:22,380 --> 00:01:23,249 will have a parameter 40 00:01:23,449 --> 00:01:25,270 named text of type string 41 00:01:25,470 --> 00:01:25,830 slice. 42 00:01:27,380 --> 00:01:29,300 The return type will be a Result 43 00:01:29,810 --> 00:01:31,669 and then we have to specify the types that 44 00:01:31,869 --> 00:01:33,680 will be returned in the success case 45 00:01:33,880 --> 00:01:36,050 and the failure case within angle brackets. 46 00:01:37,630 --> 00:01:39,579 Because, in the success case, we want 47 00:01:39,779 --> 00:01:41,589 to return an ID, the first 48 00:01:41,789 --> 00:01:43,640 type in the angle brackets will be i64 - 49 00:01:43,840 --> 00:01:45,579 the type our database 50 00:01:45,779 --> 00:01:46,980 uses for the id field. 51 00:01:48,520 --> 00:01:50,589 For the error case, we're going to keep 52 00:01:50,789 --> 00:01:51,850 this example simple 53 00:01:52,240 --> 00:01:54,340 and return a hardcoded string literal 54 00:01:54,540 --> 00:01:55,900 that describes what went wrong. 55 00:01:56,470 --> 00:01:58,329 Therefore, we specify 'static str 56 00:01:58,529 --> 00:02:00,160 slice as the second type 57 00:02:00,360 --> 00:02:01,300 in the angle brackets. 58 00:02:02,390 --> 00:02:04,250 We'll be talking more about lifetimes 59 00:02:04,450 --> 00:02:05,120 in the next unit. 60 00:02:05,580 --> 00:02:07,459 All you need to know right now is 61 00:02:07,659 --> 00:02:09,349 that 'static means a reference 62 00:02:09,549 --> 00:02:11,269 that stays valid for the entire duration of 63 00:02:11,469 --> 00:02:13,099 the program, which hardcoded 64 00:02:13,299 --> 00:02:14,160 string literals are. 65 00:02:15,780 --> 00:02:17,130 In the body of the function, 66 00:02:17,400 --> 00:02:19,320 we want to test the number of bytes 67 00:02:19,520 --> 00:02:20,190 and the status, 68 00:02:20,680 --> 00:02:22,830 and if it's over our limit of 200, 69 00:02:23,310 --> 00:02:25,230 return the Err variant of the Result 70 00:02:25,430 --> 00:02:27,140 enum containing a hardcoded 71 00:02:27,340 --> 00:02:28,980 string describing the problem. 72 00:02:30,540 --> 00:02:32,010 To finish writing this function, 73 00:02:32,490 --> 00:02:34,349 let's look at a situation where we 74 00:02:34,549 --> 00:02:36,330 want to propagate an error that 75 00:02:36,530 --> 00:02:38,370 will illustrate how to use the ? 76 00:02:38,570 --> 00:02:38,960 operator. 77 00:02:40,500 --> 00:02:42,350 In the next part of the save_status 78 00:02:42,550 --> 00:02:42,930 function, 79 00:02:43,410 --> 00:02:45,239 we want to save the status text to the 80 00:02:45,439 --> 00:02:45,950 database. 81 00:02:46,500 --> 00:02:48,479 Imagine we have a function provided 82 00:02:48,679 --> 00:02:50,369 by a library for saving to 83 00:02:50,569 --> 00:02:52,440 the database that takes a string slice 84 00:02:52,770 --> 00:02:54,869 and returns a Result that will contain 85 00:02:55,069 --> 00:02:56,850 an instance of a StatusRecord struct 86 00:02:57,050 --> 00:02:58,830 if it succeeds and a hardcoded 87 00:02:59,030 --> 00:03:00,450 error message if it fails. 88 00:03:02,010 --> 00:03:03,890 In save_status, we're going to 89 00:03:04,090 --> 00:03:05,790 call the save_to_database function 90 00:03:06,120 --> 00:03:07,680 and handle the returned Result 91 00:03:07,880 --> 00:03:09,659 with a match expression, as we did in 92 00:03:09,859 --> 00:03:10,580 the previous module. 93 00:03:12,140 --> 00:03:13,460 If we match the Ok 94 00:03:13,660 --> 00:03:15,409 variant, we want to extract the 95 00:03:15,609 --> 00:03:16,520 inner status record 96 00:03:16,910 --> 00:03:18,620 and save it in the variable record. 97 00:03:20,170 --> 00:03:21,999 Once we have the record, we 98 00:03:22,199 --> 00:03:23,440 can get the id value 99 00:03:23,640 --> 00:03:25,720 and return that from save_status wrapped 100 00:03:25,920 --> 00:03:26,030 in an Ok. 101 00:03:27,990 --> 00:03:29,690 If save_to_database fails, 102 00:03:30,270 --> 00:03:31,259 we don't want to do anything 103 00:03:31,459 --> 00:03:33,119 with the Err; we just want 104 00:03:33,319 --> 00:03:34,979 to stop what we're doing in the save_status 105 00:03:35,179 --> 00:03:35,700 function 106 00:03:36,000 --> 00:03:37,170 and return early 107 00:03:37,370 --> 00:03:39,419 with the error for whatever code is calling 108 00:03:39,619 --> 00:03:40,710 save_status to handle. 109 00:03:41,810 --> 00:03:43,950 This pattern of extracting a success 110 00:03:44,150 --> 00:03:45,859 value and propagating an Err 111 00:03:46,059 --> 00:03:48,080 value is so common in Rust 112 00:03:48,410 --> 00:03:50,240 that the ? operator was added 113 00:03:50,440 --> 00:03:51,350 to have this behavior. 114 00:03:53,040 --> 00:03:55,140 We can replace this match expression 115 00:03:55,470 --> 00:03:57,490 with only a call to the save_to_database 116 00:03:57,690 --> 00:03:59,579 function followed by a ? 117 00:03:59,779 --> 00:03:59,970 , 118 00:04:00,540 --> 00:04:02,430 and this code will have the same behavior 119 00:04:02,630 --> 00:04:04,490 written in a much more concise way. 120 00:04:05,650 --> 00:04:07,659 There's a bit of automatic conversion 121 00:04:07,859 --> 00:04:09,920 that ? does for you as well, 122 00:04:10,520 --> 00:04:12,470 which we'll discuss in the future module 123 00:04:12,670 --> 00:04:13,650 on custom error types. 124 00:04:15,370 --> 00:04:17,229 Now the save_status function is 125 00:04:17,429 --> 00:04:17,680 complete 126 00:04:18,220 --> 00:04:20,179 and this code compiles successfully. 127 00:04:21,899 --> 00:04:24,089 As an aside, before the ? 128 00:04:24,289 --> 00:04:25,980 operator was added to the language, 129 00:04:26,340 --> 00:04:28,200 it was implemented as a macro called 130 00:04:28,400 --> 00:04:28,620 try!. 131 00:04:29,000 --> 00:04:30,570 If you're reading old code 132 00:04:30,770 --> 00:04:32,610 and see calls to the try! macro, 133 00:04:33,150 --> 00:04:34,860 know it serves the same purpose 134 00:04:35,060 --> 00:04:36,120 as ?. 135 00:04:37,610 --> 00:04:39,650 Now that we've covered what ? 136 00:04:39,850 --> 00:04:41,570 does, let's talk about 137 00:04:41,770 --> 00:04:43,220 where we can use ?. 138 00:04:44,730 --> 00:04:46,590 If we try to use ? 139 00:04:46,790 --> 00:04:47,790 in a function like this 140 00:04:47,990 --> 00:04:49,900 add_five function that returns 141 00:04:50,100 --> 00:04:50,810 i32, 142 00:04:51,230 --> 00:04:53,579 we'll get an error that says the `?` 143 00:04:53,779 --> 00:04:55,409 operator can only be used in 144 00:04:55,609 --> 00:04:57,150 a function that returns `Result`. 145 00:04:58,740 --> 00:05:00,810 This is because of the early return 146 00:05:01,010 --> 00:05:02,909 of an Err that the question mark 147 00:05:03,109 --> 00:05:04,859 does, as we saw in 148 00:05:05,059 --> 00:05:05,850 the last example. 149 00:05:07,360 --> 00:05:09,369 The signature of the function in which 150 00:05:09,569 --> 00:05:11,320 we use the ? operator 151 00:05:11,770 --> 00:05:13,750 needs to allow for the Err variant 152 00:05:13,950 --> 00:05:14,860 to be returned. 153 00:05:15,460 --> 00:05:17,230 So, it needs to have a return type 154 00:05:17,430 --> 00:05:19,329 that matches what we're using ? 155 00:05:19,529 --> 00:05:19,720 on. 156 00:05:21,280 --> 00:05:22,930 In the add_five example, 157 00:05:23,200 --> 00:05:25,390 if we wanted to be able to use ? 158 00:05:25,590 --> 00:05:27,549 here, we can change the return 159 00:05:27,749 --> 00:05:29,460 type to be Result 160 00:05:29,660 --> 00:05:31,240 ParseIntError 161 00:05:31,680 --> 00:05:33,790 and change what we return to be wrapped 162 00:05:33,990 --> 00:05:34,980 in an Ok variant. 163 00:05:36,570 --> 00:05:38,469 There have been some improvements to the ? 164 00:05:38,669 --> 00:05:39,810 operator recently. 165 00:05:40,290 --> 00:05:41,720 Let's talk about those briefly. 166 00:05:43,290 --> 00:05:45,300 When the ? was introduced, 167 00:05:45,500 --> 00:05:47,340 you could only use it on instances 168 00:05:47,540 --> 00:05:48,540 of the Result enum. 169 00:05:49,530 --> 00:05:51,180 As of Rust 1.22, 170 00:05:51,720 --> 00:05:53,909 you can use ? on Option values 171 00:05:54,109 --> 00:05:54,390 as well. 172 00:05:55,890 --> 00:05:57,979 Here's an example using ? 173 00:05:58,179 --> 00:05:58,780 on Option. 174 00:05:59,540 --> 00:06:01,580 The behavior of ? an Option 175 00:06:01,780 --> 00:06:03,510 is that it extracts a value from the 176 00:06:03,710 --> 00:06:04,370 Some variant 177 00:06:04,760 --> 00:06:06,480 and returns a None variant early, 178 00:06:06,680 --> 00:06:07,550 if it finds one. 179 00:06:09,110 --> 00:06:11,080 This function will return a Some 180 00:06:11,280 --> 00:06:13,010 variant containing the last number 181 00:06:13,210 --> 00:06:13,810 plus 5, 182 00:06:14,240 --> 00:06:16,270 if there is a last number in list. 183 00:06:16,910 --> 00:06:18,740 If there isn't, this function 184 00:06:18,940 --> 00:06:20,360 will return a None variant. 185 00:06:20,870 --> 00:06:22,490 The same restrictions apply. 186 00:06:23,150 --> 00:06:25,009 Using ? on an Option 187 00:06:25,209 --> 00:06:26,839 value must be done within 188 00:06:27,039 --> 00:06:28,820 a function that also returns Option. 189 00:06:30,380 --> 00:06:32,239 The next improvement was added in 190 00:06:32,439 --> 00:06:33,650 Rust 1.26 and 191 00:06:34,250 --> 00:06:36,319 enabled using ? to return 192 00:06:36,519 --> 00:06:37,730 Result values in main. 193 00:06:39,280 --> 00:06:41,320 The main function is a special function 194 00:06:41,520 --> 00:06:43,420 that is the entry point for a binary. 195 00:06:44,990 --> 00:06:46,790 Before Rust 1.26, 196 00:06:47,180 --> 00:06:48,890 main couldn't return a value. 197 00:06:49,400 --> 00:06:51,260 So, attempting to use ? 198 00:06:51,460 --> 00:06:53,240 in the main function would result 199 00:06:53,440 --> 00:06:54,100 in the same error 200 00:06:54,300 --> 00:06:56,089 we saw before about only 201 00:06:56,289 --> 00:06:57,920 being able to use ? 202 00:06:58,120 --> 00:06:59,570 in functions that return Result. 203 00:07:00,080 --> 00:07:02,090 There was no way of fixing this error 204 00:07:02,450 --> 00:07:04,190 other than using a match expression 205 00:07:04,400 --> 00:07:06,790 to handle the result instead of ?. 206 00:07:08,320 --> 00:07:09,670 In Rust 1.26 207 00:07:09,870 --> 00:07:11,930 and later, you can add a Result 208 00:07:12,130 --> 00:07:13,929 return type to main, plus 209 00:07:14,129 --> 00:07:15,789 return an Ok variant at the end 210 00:07:15,989 --> 00:07:16,300 of main 211 00:07:16,900 --> 00:07:18,990 and this enables the use of the ? 212 00:07:19,190 --> 00:07:20,860 operator in main on results 213 00:07:21,060 --> 00:07:21,280 only. 214 00:07:22,800 --> 00:07:23,940 In Rust 1.28 215 00:07:24,140 --> 00:07:25,949 and later, test functions have 216 00:07:26,149 --> 00:07:28,050 the ability to have a Result return type 217 00:07:28,250 --> 00:07:29,909 in a similar way so that you 218 00:07:30,109 --> 00:07:31,840 can use ? in tests too. 219 00:07:33,430 --> 00:07:34,360 In this module, 220 00:07:34,750 --> 00:07:36,699 we discussed how to return the Result 221 00:07:36,899 --> 00:07:38,589 type from your own functions by 222 00:07:38,789 --> 00:07:40,719 choosing and specifying a Success 223 00:07:40,919 --> 00:07:41,350 value type 224 00:07:41,560 --> 00:07:42,820 and an Error value type. 225 00:07:44,360 --> 00:07:46,190 We looked at the ? operator 226 00:07:46,390 --> 00:07:47,980 and how it propagates errors. 227 00:07:49,540 --> 00:07:51,519 We discussed how ? can only 228 00:07:51,719 --> 00:07:53,589 be used in functions that return the type 229 00:07:53,789 --> 00:07:54,880 ? is called on, 230 00:07:55,480 --> 00:07:57,280 and we went over recent improvements 231 00:07:57,480 --> 00:07:59,020 that allow using the ? 232 00:07:59,350 --> 00:08:01,300 with the Option type, in main, 233 00:08:01,660 --> 00:08:02,620 and in tests. 234 00:08:04,170 --> 00:08:06,029 In the next module, we'll go 235 00:08:06,229 --> 00:08:07,970 over the advantages your programs 236 00:08:08,170 --> 00:08:10,480 gain from Rust's error handling strategy.