WEBVTT 0 00:01.360 --> 00:02.590 Welcome back! 1 00:02.590 --> 00:07.760 Lastly, you learned how to use pointers with the log parser program. 2 00:07.930 --> 00:13.750 ou are going to understand why you might want to use only the pointers for all the functions 3 00:13.750 --> 00:20.720 that work with a parser value. Before talking about the value versus pointer semantics, 4 00:20.720 --> 00:24.020 let's refactor the error handling. 5 00:24.030 --> 00:26.290 Let's take a look at the main function. 6 00:26.320 --> 00:30.280 Why does it need to check for an error on every iteration. 7 00:30.370 --> 00:32.190 Doing so is not clear. 8 00:32.260 --> 00:34.420 Let's do it only once. 9 00:34.420 --> 00:37.390 So I'm going to remove the error handling from here. 10 00:37.480 --> 00:40.240 So what is the best way to detect the error 11 00:40.240 --> 00:47.530 only once. Remember, I'm using pointer mechanics here, so I can save the error in the parser value and I 12 00:47.530 --> 00:50.230 can check for it only once. 13 00:50.230 --> 00:57.300 Now I'm going to print the error only once after printing the results like so. As you can see, here, 14 00:57.360 --> 01:01.170 I'm getting the error from the parser. lerr means 15 01:01.170 --> 01:04.600 the last error, by the way, you'll see how it works in a minute. 16 01:04.710 --> 01:08.920 So let's go to the parser declaration, and add an error field there. 17 01:10.190 --> 01:12.780 Now it cannot detect the errors. 18 01:12.860 --> 01:14.720 Let's go to the parse function. 19 01:14.930 --> 01:18.050 First, I'm going to remove the error result value. 20 01:18.050 --> 01:20.870 Next, I'm going to save the errors to the parser 21 01:20.900 --> 01:27.780 like so. I also need to declare an err variable here because now I don't declare it in the result 22 01:27.780 --> 01:28.340 value. 23 01:29.570 --> 01:34.750 Let me also remove the return from here because the next return already returns. 24 01:34.760 --> 01:39.630 Now let's get back to the main. The parse function returns a single value. 25 01:39.830 --> 01:43.270 So I'm going to remove the blank identifier from here. 26 01:43.310 --> 01:43.820 Cool! 27 01:43.860 --> 01:46.490 Now it can detect and print the error. 28 01:46.490 --> 01:50.840 However, it continues parsing and updating the parser. 29 01:50.840 --> 01:53.990 That is why it prints a negative result here. 30 01:53.990 --> 01:56.570 So let's prevent it. To do that, 31 01:56.570 --> 01:58.450 let's go back to the parser. 32 01:58.640 --> 02:02.280 I'm going to put a guard here, as the first statement like so. 33 02:02.300 --> 02:07.950 So if there was a previous error the function will simply return. 34 02:08.160 --> 02:11.490 Now there is a different output but it's still not good. 35 02:11.490 --> 02:16.720 It's because when an error occurs, I also need to prevent updating the parser. 36 02:16.830 --> 02:26.000 So let's go to the update function, and put a guard also there. Awesome! When it detects an error 37 02:26.050 --> 02:27.640 it doesn't process the rest. 38 02:28.150 --> 02:29.830 Let's go back to the main function. 39 02:29.950 --> 02:37.640 I'm going to introduce another function for the errors like so. It takes a slice of error values. 40 02:37.770 --> 02:44.780 Let's move the error handling like so. Instead of checking errors like this, let's do it in a loop. 41 02:44.780 --> 02:47.840 If there is an error, I'm going to print it like so. 42 02:48.290 --> 02:51.020 Let me remove the rest of the code as well. 43 02:51.020 --> 02:53.900 Now I'm going to call it from the main function. First, 44 02:53.940 --> 02:58.910 I'm going to create an error slice and I'm going to get the error from the scanner. 45 02:58.910 --> 03:04.320 Lastly, I'm going to get it from the parser. Cool, it works! 46 03:04.390 --> 03:07.840 I can handle the errors like so because in Go, 47 03:07.840 --> 03:13.180 errors are values. But I think exposing the error value is not good. 48 03:13.180 --> 03:19.780 I can introduce a function to do that, so that, I can control what the return. In addition to that, you 49 03:19.780 --> 03:25.990 should always try to expose the struct fields as little as possible, so that, if you change one of them (the fields) 50 03:25.990 --> 03:28.790 later on, the other code won't break. 51 03:28.780 --> 03:32.080 Okay, let's introduce the function in the parser. 52 03:32.080 --> 03:38.060 I need to get the error from the parser. So, I'm going to declare the parser as an input value. Here, 53 03:38.140 --> 03:41.600 I don't use a pointer because I don't need to change the parser. 54 03:41.920 --> 03:44.020 I'm only going to read from it. 55 03:44.050 --> 03:45.970 I also need to return the error. 56 03:45.970 --> 03:49.500 So I'm going to declare an error result value. 57 03:49.510 --> 03:56.880 Lastly, I'm going to return the error from the parser like so. OK. Let's use the function from the main 58 03:56.880 --> 03:58.140 function. Here, 59 03:58.170 --> 04:02.600 I'm going to get the error from the error function like so. Excellent! 60 04:02.630 --> 04:03.650 It works! 61 04:03.720 --> 04:10.340 OK. Now it's time to talk about whether a function should accept a pointer or a bare value. 62 04:10.340 --> 04:12.600 Let's take a look at the parser functions. 63 04:12.830 --> 04:17.700 Let me fold all the functions by selecting "fold all" from here. 64 04:17.720 --> 04:18.400 OK. 65 04:18.680 --> 04:22.880 Let's take a look at the functions that use value semantics. 66 04:22.880 --> 04:25.560 newParser returns a parser value. 67 04:25.790 --> 04:34.100 err takes a parser value. We use value semantics because these functions do not change the parser values. 68 04:34.100 --> 04:37.990 Now let's take a look at the functions that use pointer semantics. 69 04:38.240 --> 04:42.980 Both the parse and update functions take a pointer to the parser. 70 04:43.070 --> 04:50.060 These ones use the pointer semantics because they change the parser values. For example, the update function 71 04:50.170 --> 04:50.830 changes 72 04:50.840 --> 04:59.160 the given parser value like so. As you can see, all of these functions work with the same type: parser. 73 04:59.270 --> 05:06.180 However, they are inconsistent because sometimes they take pointers sometimes they take values. 74 05:06.290 --> 05:08.180 When you're building a program. 75 05:08.210 --> 05:11.000 Your first goal should be being consistent. 76 05:11.030 --> 05:17.770 It is better to use the same semantics. Since the parse and update functions change the password values, 77 05:17.790 --> 05:22.530 let's change all of these functions to work with pointers instead. 78 05:22.550 --> 05:27.530 First, I'm going to return a pointer from the newParse function like so. Next, 79 05:27.620 --> 05:31.530 let's change err function to take a pointer instead. By the way, 80 05:31.560 --> 05:34.580 When you return a pointer from a function, as in here, 81 05:34.580 --> 05:42.430 the runtime will keep the pointed value alive until the pointer variable goes out of scope. 82 05:42.440 --> 05:45.430 Let's go to the main function. 83 05:45.440 --> 05:48.140 Now the P is a parser pointer. 84 05:48.140 --> 05:51.300 So let's send p values directly. 85 05:51.350 --> 05:54.500 Let's also accept a pointer in the summarize function. 86 05:55.950 --> 05:57.320 It works! Good. 87 05:57.360 --> 05:59.300 I think the program is consistent now. 88 05:59.310 --> 06:07.110 Notice that, I only use pointer semantics for the parser type but I use value semantics for the result 89 06:07.110 --> 06:07.710 type. 90 06:07.880 --> 06:14.280 It's because, throughout the program I only use the result type as a (bare) value. So being consistent is the 91 06:14.280 --> 06:16.100 key. 92 06:16.120 --> 06:23.040 While refactoring the code, let's go to the parser and change some names. You know we Gophers don't like 93 06:23.040 --> 06:25.450 long names in shorter scopes. 94 06:25.620 --> 06:31.740 For example, the parse function's result value is already clear: It returns a parsing result. 95 06:31.740 --> 06:40.790 Now, I'm going to rename it like so. Let's also change the update function's result value in the same way. 96 06:40.810 --> 06:43.490 Next, I'm going to remove these declarations. 97 06:43.690 --> 06:47.710 Instead, I'm going to get them from the parsing result directly. 98 06:47.710 --> 06:51.400 First, I'm going to get the domain name from the parsing result like so. 99 06:54.260 --> 06:54.510 OK 100 06:54.530 --> 06:59.750 Now I'm going to get the number of visits from the parsing result as well. 101 06:59.770 --> 07:02.100 Now let's go to the summarize function. Here, 102 07:02.110 --> 07:04.380 I'm going to directly get the visits from the map 103 07:04.390 --> 07:04.890 like so. 104 07:07.720 --> 07:08.210 Good. 105 07:08.350 --> 07:11.230 It still works. Congrats! 106 07:11.230 --> 07:15.340 Now you know how to work with pointers and memory addresses. 107 07:15.360 --> 07:15.630 You've 108 07:15.630 --> 07:18.100 also learned when to use pointers, 109 07:18.100 --> 07:22.480 and why do you need to use them. See you in the next section!