So you will see used methods and interfaces in your own programs because they are
the bread and butter of go. But it's worth reviewing some of the
subtleties around pointers and values in methods, to make sure that they are
well, understood and also is possible to have
method values that is to take a method and treat it as a value
in the program and sometimes that can be handy. So, to illustrate all of this, I've
created a new package called Yelling, which has a
type called a loud.
String and allowed string is a string that is only ever in upper case in it. Make sure it
is and I've added a few methods here. So I've got a simple method which is to
create one of these things. It creates an empty one and it returns
one here and it's not a pointer, it's just a simple
instance of this string and then I've got a couple of methods on
it. So the string method which coincidentally is the Stringer
interface is going to just return the string itself. So the S is
stored in it.
Can call change on the string, to change the string. And that's where it actually makes sure that it's
been uppercase to make sure it's shouting. And there's another method called blank which will
actually blank out the string. And I've deliberately
made a sort of error or at least done something a bit inconsistent here which is that
here, this method is a pointer. So this method
value here is a pointer and here it's not it's actually a copy of the
value. So if you are call these methods on
an instance of loud,
String in the ones where you've got a star here, you guys are going to be piloting a pointer,
which means you can successfully modify it. And here, you're passing a copy
of the value and modifying. It will notify the copy you won't modify the thing
you called with similarly here as well actually modify it
now in general it's good to use pointer receivers like this. If the
thing that the structure you're doing is using is large, if its
large and copying, it would be expensive then. It's
Not having a copy happen because when this happens you actually make a copy and in this instance it
may be okay. A stream may be small but if it was large or the structure was complex,
then using your point would be far better. So I'm going to use this to illustrate what happens and then make
some changes to it. So in my program
I'm actually importing yelling and I create one of these strings.
I change it to hello and I printed out and so that's fairly simple. I can
just go build this.
And run it and it's going to say nothing at all. Now that's a surprise because you would have
expected it to say hello all in uppercase. And the reason for that is
that here, this is not a pointer.
If I change this to a point now rather than copying the loud string, I'm going to get a
pointer to it. So, let's do this and run it. And now I
get uppercase, hello, because this lsds here
has actually changed the underlying string. A general rule is that if
you have
A package like this and you've got a mixture of pointer and non
pointer receivers. You're probably doing something a bit crazy and you should try and
stay consistent. It should be the case that you're either accessing by copy,
which is fine or you have pointers to things you've ever mixture, it can get very
confusing in general. I find myself using pointers just so I don't have to think about it too
much, the danger. Of course, it pointers is. You can get change happening underneath,
which you may not have expected. Now, another thing you can do with
methods is
You can get them, it turned into water called method values, so I just
uncomment this code and illustrate that for you.
So here you can see that I've rather than calling loud
string note, there's no braces here. I've just taken it as a
value of treated that function as it on that particular function. So what's going to happen
here is that I will be able to just call that function like that. So just a function value.
So LS2 will be a brand new function
and LS2
Sorry, brand-new loud string and LS2 itself. I can do a
similar thing notice here rather than actually calling
change with something. I'm just taking it. So I'm taking a method as a
value and now I can call change whenever I want. So, this is essentially
created a closure on that particular LS2 value, and I'll be
changing LS2. Whenever I Call change. If I just run
this
You'll see that happen. So be quiet, change with an LS2 and actually got
printed out occasionally, it can be very useful to do. This one place is super
handy, is in the net HTTP package, where you have Handler
functions for particular routes, on a, on a web page.
And you can actually have a structure, which is your server, or your
context and have methods on it, which are handlers that meet the signature for a
Handler and then just treat them as values by doing you know my server
Dot.
Root handle, a my server dot admin. Handlers, Etc. So don't be afraid to take a
method as a value. There's one other slight subtle thing that happened to you. You may
not have noticed which is that yelling dot new loud. String
didn't return itself. A pointer returned a type in an instance of
loud string. There's no Ampersand here. There's no star here
yet. When I called change, for example on it, I was
calling a pointer receiver, and go has quietly.
Noted this what it's done is it said well this is actually really the same. As that is said,
I'll take the address of Ls and I'll pass that over. I'll turn it into a pointer
automatically. So that means you don't have to think about this is actually a
pointer or not a pointer.
Does a couple of subtle things you can do with interfaces that
I'd like to talk about in particular, not implementing them completely
and also verifying whether something meets a particular interface
and you can do that by a couple of methods. I'm going to go
into my yelling package here and I've defined
myself and interface here to say that something is a yeller if it has
these methods on it, so string, change blank and
Len which will look familiar. From what
And here, and I can use this
perfectly normally so I just run that program doesn't make any difference as it currently is. But
let's suppose I wanted to determine whether something like LS,
actually was a yellow met that interface. So if you're fairly
simple way of doing that, you define a blank variable, I want to doesn't
exist and you say
Of this particular interface type.
You try to do that, you're trying to assign that thing to a particular interface and then you
build it. And at compile time it's going to actually
try and check the the types of that. And there's a problem
because as it's saying here this thing
isn't a yellow because it hasn't got the Len method. And as you may have
noticed, I didn't actually implement the Len method so I've just implement
it.
This,
I'm going here. We'll just make this turning into
I'll pray exciting method and let's build it again and now he
builds correctly. So verifies that, that particular interface is something
that loud string actually. Implements completely obviously don't have to
do that for your own interfaces. You could go in here and say, by the way, is it
a format Stringer? So remember that implemented?
Actually, let's look at the Stringer interface. See what it actually is.
So format Stringer. Is this just has to have a string method that returns a
string and I have one of those right here.
So let's just check same thing.
Yep, so we know that as a format Stringer, so they can be handy if you want to build
time, verify the something implements particular interface. Now, what
about not implementing something? So, for example, if I go back here, let me
just remove Len again.
And we move the check.
And we'll say, We'll declare within hear that loud string.
Implements that interface. So we've said here go, this is an interface it implements
but Len is missing. So first of all program
builds fine, it doesn't complain. That Len is missing. What happens if I try and
access it? Well, let's try and do that.
So LS, do dot then
Feels fine panics as you not really as a prize is trying to call the
method which doesn't exist and this can actually turn out to be
useful. This might seem like a disastrous thing to do, but by going in
here and declaring the loud string, Implement that interface, it
is now a yellow. If you didn't need to call Len,
then it would be okay that it wasn't implemented. Now that might seem very strange but there's a very
good situation in which you might want to do that, which is in a test Suite.
If you wanted to test some subset of this yella
interface within a test Suite without having to implement everything in a concrete
type, then you could do this. You could say in here, you could embed within a type like
the structure. Yes, I'm commit. Yella that can be passed anywhere where a yeller
is acceptable, but if you don't call the things that are implemented, it's
okay you'll be able to do it. I wouldn't recommend doing this in the main
line of the code but this is the sort of useful work around in the test Suite when you want to pass
something around without having to
Mock up a whole load of functions which you may never actually need to use. So I've
declared that loud string is a yellow but I haven't implemented.
One of the methods in the interface, the Len interface nevertheless. I can still use
my little VAR trick just to verify so I'm just say
is this thing?
A yellow just run to that build and yeah sure enough it is.
So, despite the fact that is not implemented, it is a yellow. And therefore can be passed
anywhere that a yellow is needed.