- So we're gonna have a look at a demo.
For this lesson, all the demos are in this project,
lesson04_enums.
I created this project using Cargo, let's take a look.
So here it is on my file system in rustdev, lesson04.
It's a Cargo project,
so if you open that project in the code editor,
I'm gonna open that project in VS Code.
So here it is, here's my project in VS Code.
And if you look in the source folder,
ignore this file for now,
we'll discuss that later on.
Just for now, notice mytypes.rs,
I define an enum type called color
with the variance red, green, and blue;
and that enum is public.
I define another enum type called house location,
let's ignore that for now,
we'll discuss that later on in this lesson
so imagine that that didn't exist for now.
And we'll just concentrate on the color enum type.
So mytypes.rs is a module file,
in order for that module to become part of my application,
even though it's part of the directory structure
it isn't actually part of my application unless I load it.
And you load it from the top level,
in your top level file main.rs, it looks like this.
You load mytypes, like so.
It effectively will look for mytypes.rs,
and that code in there gets imported at this point here,
it's like an import statement in other languages, okay?
And then I've introduced the color enum type
and the house location enum type into scope.
It means I can use these enum types directly in my code now.
I could have split this into two separate statements,
I could have written it like this
and I just do a bit of copying and pasting.
I could've imported the color name if you like, symbol name,
from mytypes into scope,
and then separately I could have imported
the house location also into scope.
Okay, so you can input that type into scope,
into the current scope from that module,
and you can input that type into scope from that module.
Because they're located in the same module,
then it makes sense to group them together,
so you would do that.
From the mytypes module introduce that name
and that name into scope,
it means I can use these names directly now in my code.
There's some other examples we're gonna look at later on,
we're gonna be talk looking at mytypes
for demo purposes later on,
which is kind of similar but slightly different.
So I'm gonna ignore that for now,
and we'll ignore this for now,
we'll come back and look at that later on,
okay, when we're ready.
Okay, let me just show you what functions I've got.
These are all the functions for this lesson,
so like we had in the previous lesson
I've got a main function
which is kind of like the driver for the demo,
and then it calls one of several other functions
depending on which part of the demo I want to run.
So there's a function here which demonstrates simple enums,
I'm going to uncomment that,
and let's have a look at the code in here.
Basically the code in here
is what we showed in the PowerPoints.
So it demonstrates simple enums,
it declares a variable of type color and it's color red,
and then we match on the color,
we output either coch, gwyrdd, or glass.
Right, so I'm gonna run this application several times
because I've got several different things I wanna show,
so let me open up the terminal window.
Now I'm gonna warn you in advance,
when I run the application
I'm gonna get quite a lot of warnings about dead code, okay?
So I'll run it
and then I'll explain what the warnings are,
and then we'll see how to kind of look
at some other techniques as well.
So let's just do a cargo run, first of all.
So I'm gonna make this a bit bigger,
I'm just gonna show you what the warnings were.
There were six different warnings, I think.
Some of the warnings we kind of know about already,
I've got a function demo enum with data,
it's complaining that I've got that function
but I've never used it.
I've got another function called demo using option enum,
option is one of the built-in enum types,
it's complaining that I've not used that function.
"Why have you written it?"
Well, you know, because it's just a simple demo.
Oh, I've got another function here, second of day.
That's a curious one, second of day.
We'll have a look at that later.
And other functions as well,
which is also complaining about
this demo using result enum,
result is another enum type in Rust.
So it's complaining about the functions that exist
but haven't yet been called,
but also it's complaining
I've got an enum type called house location.
If I remind you, right at the top,
I imported the house location.
Well, actually what I did, I imported the module, mytypes,
and in there it has the color enum, which I'm using,
it has the house location enum which I'm not using yet,
I will do later, but I'm not using it just yet.
In the code it's saying, "Why have you defined this enum
if you're not using it?"
Well, because I haven't got round to it yet is the answer,
but it's still giving me a warning.
So, well, yeah, so there we are.
And then it actually output what I was hoping to output,
so back in main what I called my simple function here,
it outputs the kind of header message,
a demo of simple enums.
I declare my enum variable,
I test its type, and it's red,
it outputs coch like so.
Right, so those warnings,
I'm gonna tidy my code up a bit later
to get rid of those warnings,
but for now we'll just kind of ignore them.
A couple of things I wanted to say.
First of all, what would happen...
I tell you what I'm gonna do, actually, I'm gonna delete,
I'm gonna temporarily delete these other functions, okay,
because we don't need them just yet.
We'll just have this simple function
just to get rid of some of those warnings.
Okay, so what if I didn't include the mod statement?
Okay, let's comment that line out,
and I'll comment this line out as well.
So if you don't declare the module,
then it never bothers
processing the code in that module, okay?
So this keyword, this here is required
to kind of import the code.
If I don't import the module,
if I basically comment out line two,
then I try to run it, cargo run,
watch what error message I'm gonna get.
It complains here on line 23,
it says, "What is this color type?
I've never seen it before."
Okay, to which I might say as a programmer,
"But I defined it over here, color enum."
But the compiler would reply back to me
because we're having a dialogue here,
me and the compiler, the compiler would say,
"Yeah, but you never told me
to input that module, did you Andy?"
And I would say, "Oh, thank you very much.
That's very polite of you, dear compiler.
Now I see what I've done wrong."
Now I have imported that code, okay,
so that code will now be processed.
You have to actually import it like so.
So, good, I've still got this line
commented out though, notice.
Okay, whoops. So that line is still
not kind of being processed.
So what would happen
if I tried to run the application again?
Well, another error.
Now it's saying, what's it saying here,
what's the first error message?
Again it's saying, "Use of undeclared type color."
So the problem is, a module is kind of like a namespace.
When you declare a module at mytypes,
this name is effectively in a namespace, mytypes, okay?
So if you wanted to use it
you'd have to qualify it by its module name.
So what I could do is I could say,
"Okay, everywhere I'm using the color type
I need to tell it that that's part of the mytypes module,"
like a namespace, and the :: is like a scope operator.
So go to this module, which is like a namespace,
in there you'll find the color type, yes,
and it has the red variant.
That's good, but I'd have to use this prefix everywhere
where I've referenced the type name,
and already I'm starting to get a bit fed up with this,
having to qualify it by its module name everywhere.
"But that would actually work," he says.
Let's that a quick run, that will actually work.
Okay, so that has actually worked there.
Couple of warnings but it has actually worked, okay.
So, yeah, that's basically the idea of the use keyword,
rather than having to fully qualify color by its typing
you can bring it into scope.
The use keyword basically brings that symbol name
into top level scope,
so the color symbol is now, from mytypes,
is now directly in scope.
So it's kind of almost like a global symbol name now
in my code, and I don't any longer
need to use the mytypes prefix,
it's already been dragged into scope by the use keyword.
So the mod keyword actually physically imports the code file
and the used keyword introduces a name into scope,
so you can just use that name directly
without attempt to prefix by its module name, like so.
Okay, so that hopefully explains the mod keyword
to import a module, to basically drag the code in,
and the use keyword to give you
direct access to those names
directly in the current scope of your current file,
without the name, for the module name as a prefix anywhere.
Okay, I feel like I should run it again.
So it's working again and it outputs coch.
Couple of other things,
which I'll just finish off by mentioning.
Here, when you declare a variant, a variable, sorry,
and you give it an enum variant,
you don't really need to type it.
You don't need to specify it's a color,
it can guess that it's a color.
By virtue of the fact that you've given it
one of the color variants, it knows that it's a color.
Okay, so that would actually be a little bit better.
Okay, so that is working still.
And just one last thing,
you still need to specify the enum type
in front of the variant, he can't do that, okay,
because red, green and blue
might, for example, be variants on another enum type.
You might have like a political party in the UK,
green is a political party in the UK.
So that wouldn't work, you're gonna get an error here.
If I run the compiler again it will say,
"I don't understand what you're talking about here,
I've lost it. This symbol name is not understood."
Okay, oh, right, so basically I need to scope it like so.
Okay, so the actual process
of defining enum types is quite straightforward,
remember to make it pub so it's kind of visible elsewhere.
The variants are always public when you have an enum.
The interesting part, really,
most of our discussion here is about organizing our code.
I've put it into a module file so it can be imported
in lots of other applications, potentially.
In my main code, I input that module,
technically I'm declaring the module,
I'm dragging that module file into my application,
I'm introducing these names directly into scope
so I can use them without qualification.
Right, okay, so I think there's one other thing
I want to discuss,
let me just run the compiler one last time.
(keyboard keys clacking)
Note this, I'm still getting some warnings.
I'm gonna look at this one in here.
It sees my color enum and my color enum has three variants,
red, green, and blue,
and it's complaining
that I'm not using the green or the blue variant.
Technically they never constructed,
it means my code never seems to make use of color blue.
I'm not actually creating a variable
of color blue or color green,
obviously because it's such a small example
I don't need to.
In a large application, hopefully all of these enums,
all of these variants
would kind of crop up somewhere in my code.
At the moment, it's complaining
that there are variants here that aren't being used,
"Why are you declaring these variants
if you're not using them?"
Okay, so the solution to that dilemma
we're gonna look at in the next section.