- In the previous section,
we saw how to define enums that can convey values
in their variance.
It's a very useful mechanism and it's used a lot
in some of the standard enums in the rust library.
And here's a good example, the option enum type.
Basically it represents a value that may be there
or may not be there.
It's kind of the equivalent of an optional variable
in Java or an nullable variable in .net, okay?
It may have a value or it may have no value at all.
It's like an optional value.
So in terms of the syntax, option is a generic type.
When you create an option,
you've gotta tell it what type T represents,
like an integer for example,
and then when you create an option value
it can either be in the state sum,
in which case it contains a value of that type,
like an integer, or it can be in state none,
which means it doesn't represent,
it doesn't have a value at all.
So it represents an optional value.
It might contain a value of some type T
if it's in this state
or if it's in this state, it has no value at all.
The main reason or one of the main reasons
for using option is to represent a nullable type
that could be returned from a function.
For example, you call the function
and in other languages if you wanted to indicate, you know,
that the function failed, you might return null.
But working with null is quite dangerous.
You can get into, kind of, null point of exceptions
and the program crashes.
So rust doesn't really have the concept of null.
It has an option, instead.
Whenever you want to say,
this function may return a value or it might not
then you return an option, okay?
And then the caller,
when they get the option value back,
they can check, does it contain some value
or does it contain no value at all?
Safer than dealing directly with null pointers.
It avoids potential null point of exceptions
that you might get in other languages.
So here is an example.
I've got a function called second of day,
and you pass in the hour, the minute,
and the second of a current time
and the function, this is how you designate the return type
of a function at the end of the function signature,
the function takes in an hour as an unsigned 32 bit integer,
the current minute and the current second
and it returns an option, okay?
So it's gonna return you the current second of the day
from midnight, but maybe it doesn't return the value at all.
So hopefully it'll return some value of type u32
or maybe it'll return none.
So what it does, it basically does an error check in.
It says, if the hour is less than 23, oh, first of all,
because the hour is unsigned,
then it can't be negative, okay?
So it could only be zero or above,
if it's less than or equal to 23,
and if the minute is less than or equal to 59,
and if the second is also less than or equal to 59,
then that's valid.
In which case we return
or we calculate how many seconds there are past midnight.
There were 3,600 seconds per hour.
There were 60 seconds per minute,
plus whatever the seconds are into the current minute
that will give you the number of seconds
that you are into the day.
A bit contrived, but there we go.
And it returns Option::Some.
This is how you create an option variable.
You give it the variant type - some
and because it was defined to be a u32
we give it a u32 value.
Secs, seconds here is an unsigned 32 bit integer.
So the function will hopefully return some u32 value
or it'll return none.
It'll either be in that state
in which case it contains a value of interest
or it's in this state, which means effectively it failed.
Now as a C++ developer, or Java developer,
or something like that,
you might have been tempted return null in this case
to represent failure.
Null is a very dangerous thing in programming.
An option is a safe alternative
to using raw null pointers.
Right, when I call this function,
I can then check the option that came back.
Does it contain some value?
In which case, give it to me
or did it contain no value at all?
So let's see how to call that function
using the match statement to extract the value
that it might contain.
Right, so I've declared this here.
My return variable if you like, of type option u32,
I call the function,
I pass in some hours, some minutes, some seconds.
It'll return an option of u32 into this variable,
which I then test, does it contain some value?
In which case give me the value
and it'll print out the second of the datas
and then the result.
Or alternatively,
if the function returned an option in state none,
then that indicated an error condition, really.
So, second of day, no value, all right?
So this is really commonly used.
Take an option variable
and then test to see whether it contains some value.
Remember that was the name of the variant
or whether it contains no value at all, none.
Right, because options are so popular,
there are lots and lots and lots
and lots of functions in rust within option
to say maybe a value, maybe not
because it's such a common concept,
because it's such a common requirement
to kind of extract the value out of an option.
There's a function called unwrap_or()
which is really useful.
It will internally, when you call unwrap_ or it does a test
and if the option contains some value
it'll give you the value
or you can specify a default value
that you'd like to get back in the case where it was none.
So it would look like this.
You'd have an option variable,
and then you'd assign it some value
and it will either contain some value or none.
You can say, give me the value or give me back zero instead.
So if it contains a value, if it contains some value,
it'll unwrap it and give it to you as a u32.
If it contains none,
then you can specify what default value to get back instead.
Okay, so this is a handy alternative
to write in a match statement.
Instead of you have to say,
does it contain some value or does it contain no value?
This does the same thing, but internally.
Give me the value if there is one
or give me back the value suitable default if it doesn't.
So it turns out unwrap_or
is just one of many functions defined in the option type.
Technically speaking, there are lots
and lots of methods available with the option type.
I didn't get full details online.
If you go into the documentation for the rust language,
if you go into the standard crate,
it has a module called option
and if you click the link,
it'll give you documentation about the option module
in the standard crate.
Let's have a look at this link.
And here it is.
So in the documentation for the rust language,
in the standard crate, there's a module called option.
Remember modules like in namespace.
And in the module option, if you scroll down
it's got some explanation here, some code,
but it also mentions that in the option module,
there is an enum.
If I just click the enums link here,
there's an enum called option.
That's what we're talking about.
We're talking about the option enum.
Let's click that link
and here it'll tell you the option enum.
Option, with a capital letter, is an enum type
defined in the option, lowercase, module in the stud crate.
And this option enum is public,
thankfully we can access it.
It contains two variants.
The variants are none and some,
and these are all the methods, functions, available.
You can call any of these methods on an option, okay?
I'm not even gonna attempt to go through this list
because it's very comprehensive.
The one we looked at was this, unwrap_or.
So the unwrap_or function.
And without getting too, kind of, tied up in the syntax
it returns the value if it contains some value
or it'll return the default that you've specified.
Okay, but there are lots of other functions as well.
Have a look through the documentation.
It's the kind of thing that you probably won't do initially,
but the more you start writing rust code,
the more you'll be looking for some functionality.
Can the option enum do some code?
And there were lots of functions here
for you to, kind of, learn as time goes by
in your rust career.
You never learn all of it,
but you learn the bits that you need to.
Okay, so let's have a look at an example of all this.
Same project as before.
Lesson four enums.
So we're gonna look at, in the main rs,
we're going to look at a function that returns an enum
sec of day and a function that calls the sec of day
and retrieves the enum and processes it.
Okay, so we'll talk through the code
and then we'll run it as normal.
Let's have a look at the code.
Right, so here we are.
This is the demo project, and in my main function,
let me uncomment, demo_using_option_enum.
Very good.
And it is, well, these are the two functions of interest.
There's the function that I talked about.
You pass in hours, minute, seconds,
it'll return, hopefully, a u32,
maybe it'll return none.
If the hours, minutes and seconds are valid,
then it will return the some value.
It'll return basically an option object
with the flag set to some
with the value that we've just computed
or if hours or minutes or seconds invalid,
then it returns none.
Effectively the equivalent in rust of a null pointer,
kind of.
So that's my function.
And then I call it up here.
So I declare available of type, option u32.
If I call the function with valid inputs
then I'll get back an option
that contains some value, okay?
So it'll say second of day
and it'll display the some value and I can unwrap it.
That's basically the same as doing a match, really,
but more concisely.
Give me the value that it contains
or zero if it doesn't contain a value.
So if I pass in 23, 59, 59, that's one second to midnight.
So just trying to do the maths here, in my head.
I think there were, is it 86,400 seconds in a day?
I'll see if I know it, cargo run,
ignoring the warnings about unused functions.
Oh, look at that.
So if it's one second to midnight,
then it's 86,399 seconds into the day,
one second before the start of the next day.
So that all worked beautifully.
Let me change my code.
Let me comment out the valid call
and comment the invalid call.
I've passed in an invalid input.
So my function will kind of fail.
Well, it's not gonna fail, but it'll say,
oh, hang on, that's an invalid hour
and it'll return an empty box, effectively.
And option is like a box.
It may contain a value,
it may contain no value at all, so it returns none.
So when I then try to pick it apart,
the option will be none.
And it'll say second of date, no value available there.
And then when I try to unwrap it here, the unwrap,
well it can't unwrap no value,
so it'll gimme back a default value instead.
So this default value, it's up to you what you give it.
Zero seemed like a good default for me.
So when I run the application now,
that's what I'm gonna see.
When I try to do an explicit match.
Second of day, no value available.
Okay, no value available, that's correct.
And then when I try to unwrap it,
it couldn't unwrap no value,
so it gave me back my supplied default instead,
which is zero.
Okay, so option very widely used.
We're gonna use that a lot in the course as we go through.
And don't forget, as well as the unwrap_or method
there's all the other methods available
in the option type as well that you can use.