Welcome back.
Lastly you refactored the log parser to functions.
Now it's time to rewrite it once more
using pointers. OK, let's take a look at the code.
newParser returns a new parser struct value. The parse function passes a line from the log file and
returns the parsing result.
Lastly, the update function updates the parser and returns a new copy.
So the main function can update its copy.
Let's take a look at the update function now. Here, if it wasn't returning a new parser, the main function
wouldn't see the changes to the sum and total fields.
However, if you use a pointer, you don't need to return a new parser value.
So let's remove the return statement from here.
Let's also remove the result value. Let's change the input value to a pointer instead.
I don't need to change anything else here.
Let's go to the main function.
Let's remove the assignment from here. It expects a pointer.
So, let's take the p variable's address.
So this sends the memory address of the P variable to the update function.
Voila!
It still works.
It's because, the update function can now update the original parser value through the pointer.
So the update function doesn't need to return a new parser value.
It can directly the update
the main function's parser value
now. Let's investigate how it works.
First I'm going to print the address of the original parser.
Let's go into the parser file. Here,
I'm going to print the address of the copy.
P is a pointer, so I don't need to take its address. So I can directly print it.
Let me also print the address of the P variable.
This is the address of the main function's parser.
It is the original parser. The update function receives a pointer from the main function, and that pointer
points to the memory address of the original parser value.
Here you can see that, they all point to the same parser value. Although each one of them points to the
main function's parser value,
they have different addresses. It's because each one is a different pointer variable. OK! Let me remove
these print calls. By the way, I think updating the parsed lines is the responsibility of the parse function.
It's because, it is the one who handles the parsing.
So now, let's move that responsibility to the parse function. Let's try it with an incorrect log file. It
reports an incorrect line now because the pass function creates a new of value. It's because it receives
a parser value, so it copies the parser value. Then it increments the field inside the parser value
here.
So the lines field always starts at zero, then it becomes one.
So this function can never update the main function's parser value. It has its own parser value.
So instead, let's get a pointer to the original parser value.
Let's go back to the main function here.
I need to pass a pointer
Cool!
Now it works!
Now the parse function can update the main function's parser value through the pointer. So it updates
the lines field as well.
Let's go to the main function.
Here's a question: What happens if you pass a new value instead?
It says there is a problem on this line.
Let's go there.
The error message says that this code de-references (indirects) using a nil pointer. Here,
it tries to get the value but the pointer doesn't point to a memory address.
So there is nothing to return.
That is why it panics and terminates the program.
So you should be careful while using pointers. Nil pointers can crash your program.
Okay let me fix it. OK, so far so good.
So what's next?
Let's take a look at the main function again.
There are two responsibilities here.
First, it parses the log file and updates the parser.
Second, it summarizes the results.
So instead of summarizing the result in the main function, I'm going to create another function to do
that
like so. It takes a parser value, and I'm going to cut the code from the main function, and I'm going to
move it into the summarize function.
I also need to call it like so. It works,
good.
So why did I use a value to the parser instead of a pointer?
It's because, the summarize function doesn't need to change it but only prints it.
Okay.
In the structs section there was a problem.
Let's remember it.
I was trying to increase the visits per domain like so. But it wasn't working because map elements are
not addressable.
So what is addressability?
Let me explain it through an example.
For example, I cannot access the memory address of a map element.
It says you cannot access the memory address of the map element.
So this means a map element is not an addressable value.
However, you can copy the map element. Then you can take its address. When you do so, it becomes an addressable
value.
You can take the address of the clone variable because it's a copy of the original map element. It is
not the original map element.
So in summary, if you can take an address of a value, then it is an addressable value.
Otherwise it is not an addressable value.
As I've said map elements are not addressable values.
It's because, sometimes Go runtime moves them on the memory without asking you.
Because of that Go doesn't allow you to take the address of the map elements.
That's why when you get an element from a map, it only returns you a copy, so that you never will be able
to access to the original map element.
All right.
That's all for now. See you in the next lecture.