Build Go Apps That Scale on AWS

Pointers & References

Melkey

Melkey

Twitch
Build Go Apps That Scale on AWS

Check out a free preview of the full Build Go Apps That Scale on AWS course

The "Pointers & References" Lesson is part of the full, Build Go Apps That Scale on AWS course featured in this preview video. Here's what you'd learn in this lesson:

Melkey dives deeper into variable references and demonstrates pointers. The ampersand symbol refers to a variable's memory address and allows a pointer to be created. If the pointer is dereferencing, it is also explained, and a demonstration of using a pointer to update the original variable's value is provided.

Preview
Close

Transcript from the "Pointers & References" Lesson

[00:00:00]
>> Cool, I really want to show that address copy because I thought it was a really cool feature and in here, let's just put back our asterisks here, so that we are going to persist the changing of our value here. Now there is another concept I want to discuss, and it's basically going to be how you can declare a variable as a pointer, to the memory address of something.

[00:00:26]
Bear with me. So let's say we have A, A is declared as an int/ that's all it is. We just print A, it's going to give us 7. Let's create B, B is going to be a pointer to A. Okay, nothing too crazy, let's print this line. And I wanna actually ask, what are we gonna get when I print B?

[00:00:52]
What is B going to be?
>> Address?
>> Yeah, the memory address, so that's what the ampersand does it doesn't print the value or what's stored in the memory, it's a pointer to where that memory was allocated to where it's pointing to. So it's gonna point us to where A is allocated memory.

[00:01:12]
So if you run this you can see here, this is B, right? It's just an address, but what if I wanna change the value of my pointer, okay? If I do something like B is now 9, can I use 9 untyped in constant as pointer and or reference INT value in assignment.

[00:01:33]
So if you want, what we have to do is called the referencing the allocated memory to actually change the value and we can use as it shows here. So this is kind of that dual meaning of the asterisk gets a little murky right now, but what the asterisk is doing now is it's saying.

[00:01:49]
I have this new int this 9, the native type that was allocated when I first instantiated A, and instead of giving the memory address or re-declare the memory address as 9 because you can't do that, we're basically saying, hey, dereference the actual value of where the memory is allocated and assign it this new int of 9, okay?

[00:02:10]
So here, if we keep the same print statement, I'm actually going to go back up here. I'm going to comment this out and clear this just for now, if I actually rerun this it's still the memory address, we haven't changed anything. But if I now dereference it, and I run it, it's 9.

[00:02:27]
But question, what is A? What if I print A what value is A gonna have?
>> 7 right?
>> 7 or 9, let's find out. If we change this to A and we re-assign it, it's 9, because B is the pointer, right? It points to the actual allocated member of A, so if we de-reference it and re-assign a value, it's going to impact the D reference B, but also A, when we first initialize that variable.

[00:03:02]
Cool, if you've never dealt with pointers or anything, it can get a little dicey, but just remember a core kind of principle is if you want to change and modify the values of the struct or the type upon instantiation declaration, you have to pass it in as a pointer reference, okay?

[00:03:18]
But if you are comfortable with just a copy of this truck for maybe logging or whatever other purpose you don't need to put it in as a pointer. Yes.
>> So your fields are all capitalized?
>> Yes.
>> Even though they're fields.
>> Yeah.
>> And then also you capitalized that function, is that because it's returning a struct?

[00:03:37]
>> No, great question, you're peeking behind the currents of the next portion, but I do want to answer it, right now, this is just like new person. It's kind of habit the way I wrote it I'm not gonna lie because here on function 10 is new person declaration capital N but for some reason, this is not capital it's a habit, because like I said earlier, when I know I'm gonna have a book person type or a person struck and I'm gonna use it.

[00:04:04]
I'm gonna probably import this function to somewhere else and declare that function to get the person right. And in go making a function public is only denoted with the capitalization of the first letter. So I'm gonna get into that into the next kind of module like model here or module, but that's a tidbit of information.

[00:04:27]
So everything that's not capitalized is gonna live in the scope of the package, everything that's capitalized can be improved by other packages. So, I'll show you an example if maybe that concept is a little wonky okay, we're almost done. This goes much deeper. I wanna go back to our looping here for a second.

[00:04:46]
>> Before we get on, can I nested struct can be copied by assigning?
>> Yes, a nested copy, if you have a nested struck and you pass it in, everything will be copied from the from the nested struck. Every time it's gonna make a new copy of whatever you pass it in, which is another point of there is that you can kind of get away, like in this kind of let's say toy example, you can get away doing passing by reference or passing by copy cause our struct has two fields it's whatever.

[00:05:17]
Our computers can eat that no problem, if you have a super long struck with multiple different fields and it has like a nested STRs passing by copy is costly. When it gets to that scale, right, that's where it might be more efficient to pass the actual reference instead of making a new copy, passing it down your logic, so you can do, you can just pass that struck by reference.

[00:05:39]
So a lot of the time you would actually see in more heavier duty code, that this function here that returns our person struck is actually always going to be the reference to to the struck here, right. You probably see something like this happen all the time, cause we wanna return a struck that's gonna be the actual reference when it's stantialized and then, we avoid passing as a copy every time we call methods on that truck, changing the property, modifying the property, aggregating it, whatever.

[00:06:12]
Any questions on that?
>> When you are dealing with copies and stuff, is there any kind of track like cleanup memory you need to do?
>> The garbage.
>> That's too far in the weeds we can.
>> No, no, no, no it's not far. No not at all, the garbage collector of go which I briefly mentioned earlier, does all that for you.

[00:06:30]
But that isn't excuse to kind of be negligible in that perspective because you still run the risk of your heap being to allocated, if you have a leaky pointer, right, if you have something it's pointing to something that's no longer used and it's massive, you run the risk of like merging your heap or going over it right.

[00:06:48]
So there's this concept that a garbage collector does a lot of things under the bed kind of under the hood for us, but you do have to be aware that does has an underlying cost and it could come back and bite you, so you have to use. That's kinda where the engineer in software program will come into and make a decision.

[00:07:09]
Really good question, thank you. Okay, one more thing about this whole topic of pointers and everything, I wanna go back to our good friend looping. So I'm gonna make a new slice. My slice, slice SIO is going to be I don't know, let's just say it's a slice and it's int, and we gonna make 1, 2, and 3, okay?

[00:07:35]
And my task is to increment these values in the slice. Pretty easy loop Add 1, okay? So let's do that, so for index value, I'm gonna use range myslice, okay? And here, because we only are interested in the value, we can do something that's pretty interesting to go.

[00:07:54]
So if there's a return value that you do not want to use, cuz if we don't use index, we're not gonna compile the compiler Is gonna keep yelling at us. I'm like, man please stop yelling at me. We can do is just put underscore here. So now we ignored it.

[00:08:05]
We essentially ignored the index and the return type, so now our compiler doesn't care, it's like, okay, I see you're ignoring it I'll shop now, but you still do not use value. Let's just do value because we need to increment value++. We increment the value, okay? If we do fmt::print, print loin and we do my slice and we save it.

[00:08:24]
If we print this, what do you all think is gonna happen? Probably you kinda figured out that's still going to be 123. So even the built-in range function, when you increment the value, it is a copy of the value in the slice, it is not the allocated reference to that slice, all right.

[00:08:46]
If you wanna actually modify the underlying value of the slice and persist it and actually allocate the memory, or change the memory, that's where we have to bring back the index. We can actually ignore this copy and what we do here is my slice referenced at the index I could type that would be really nice index ++.

[00:09:09]
And so now, if you run it, it should say 2, 3, 4 there you go. So it's another gotcha that if I introduced iterating over a slice I want to showcase how you can fix that.
>> How can you return reference of a struct wouldn't the reference then live shorter than the struct?

[00:09:32]
>> How can you return the reference of the struct? Well, you could return the reference. Let's just go back up here. With this syntax here this is returning the reference of the struck. And so every time we use that struck now we're always going to be passing the reference of that struck and never like there's no I don't know the second portion like the can you repeat it?

[00:09:57]
>> When the reference live shorter than the struct
>> I think I understand that question. So that kinda going back to what you asked earlier is, you will still always have a reference to the memory allocate to that struck. And if you do remove that struck or it's unused, you'll still have that memory allocation you saw something referencing that memory, and that's how you can have like leaking memory usage as well.

[00:10:28]
So that reference can exist past the stroke and you will be kinda referencing allocate memory that no longer exists and then that could be pretty buggy in your code.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now