Why do we use the Option enum? - enums

I don't get what the Option enum is for. I read that Rust doesn't have null values. The Option enum is defined like this:
enum Option<T> {
Some(T),
None,
}
I read its implementation and I came across this example:
fn main() {
fn divide(numerator: f64, denominator: f64) -> Option<f64> {
if denominator == 0.0 {
None
} else {
Some(numerator / denominator)
}
}
// The return value of the function is an option
let result = divide(2.0, 3.0);
// Pattern match to retrieve the value
match result {
// The division was valid
Some(x) => println!("Result: {}", x),
// The division was invalid
None => println!("Cannot divide by 0"),
}
}
When they could also do it like this:
fn main() {
fn divide(numerator: f64, denominator: f64) -> String {
if denominator == 0.0 {
format!("Can't divide")
} else {
let x = numerator / denominator;
format!("{}", x)
}
}
let result = divide(2.0, 3.0);
println!("{}", result);
}
Both programs output:
0.6666666666666666

Maybe the above example is not a very good example of Option, but the following example shows Option at its very best:
fn main() {
let name = String::from("naufil");
println!(
"Character at index 6: {}",
match name.chars().nth(6) {
Some(c) => c.to_string(),
None => "No character at index 6!".to_string(),
}
)
}
When we are not sure whether there is a character at 6th element and you don't want your program to crash, Option comes to the rescue. Here is another example from The Rust Programming Language:
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
Listing 6-5: A function that uses a match expression on
an Option<i32>
Let’s examine the first execution of plus_one in more detail. When we call
plus_one(five), the variable x in the body of plus_one will have the
value Some(5). We then compare that against each match arm.
None => None,
The Some(5) value doesn’t match the pattern None, so we continue to the
next arm.
Some(i) => Some(i + 1),
Does Some(5) match Some(i)? Why yes it does! We have the same variant. The
i binds to the value contained in Some, so i takes the value 5. The
code in the match arm is then executed, so we add 1 to the value of i and
create a new Some value with our total 6 inside.
Now let’s consider the second call of plus_one in Listing 6-5, where x is
None. We enter the match and compare to the first arm.
None => None,
It matches! There’s no value to add to, so the program stops and returns the
None value on the right side of =>. Because the first arm matched, no other
arms are compared.
Combining match and enums is useful in many situations. You’ll see this
pattern a lot in Rust code: match against an enum, bind a variable to the
data inside, and then execute code based on it. It’s a bit tricky at first, but
once you get used to it, you’ll wish you had it in all languages. It’s
consistently a user favorite.

The reason the Option enum is used for the same reason the Result enum is used. It allows the programmer to see the breadth of returning values they might receive, but without having to dig through code you don't remember all the details about, or have never seen.
Option isn't a special value, it's just an enum, like Result. You could also use something like:
enum Division_Result {
Successful(f64),
DividedByZero,
}
fn divide(numerator: f64, denominator: f64) -> Division_Result {
if denominator == 0.0 {
Division_Result::DividedByZero
} else {
Division_Result::Successful(numerator / denominator)
}
}
It just so happens that Optional values are some of the most common types of values that you have to deal with in a program. They're baked the Optional enum into standard because otherwise you would have to deal with everyone coming up with their own enum for the simple concept of an Optional value.
Returning an enum is an improvement over returning unwrapped magic values because it is more explicit to the programmer that the return value might diverge from what they wanted from the function.

Related

Is that possible to create a comparison operator from string?

I'm trying to create a function that will produce an if condition from a predefined array.
for example:
package errors
type errorCase struct {
// This is the field I need to get in another struct
Field string
// The comparison operator
TestOperator string
// The value that the expected one should not with equal...
WrongValue interface{}
}
var ErrorCases = []*errorCase{ {
"MinValue",
"<",
0,
}, {
"MaxValue",
"==",
0,
}}
Actually I made a new function with a for loop that iterate through all of these "error cases"
func isDirty(questionInterface models.QuestionInterface) bool {
for _, errorCase := range errors.ErrorCases {
s := reflect.ValueOf(&questionInterface).Elem()
value := s.Elem().FieldByName(errorCase.Field)
// At this point I need to create my if condition
// to compare the value of the value var and the wrong one
// With the given comparison operator
}
// Should return the comparison test value
return true
}
Is that possible to create an if condition like that?
With the reflect package?
I think this is possible but I don't find where I should start.
This is possible. I built a generic comparison library like this once before.
A comparison, in simple terms, contains 3 parts:
A value of some sort, on the left of the comparison.
An operator (=, <, >, ...).
A value of some sort, on the right of the comparison.
Those 3 parts, contain only two different types - value and operator. I attempted to abstract those two types into their base forms.
value could be anything, so we use the empty interface - interface{}.
operator is part of a finite set, each with their own rules.
type Operator int
const (
Equals Operator = 1
)
Evaluating a comparison with an = sign has only one rule to be valid - both values should be of the same type. You can't compare 1 and hello. After that, you just have to make sure the values are the same.
We can implement a new meta-type that wraps the requirement for evaluating an operator.
// Function signature for a "rule" of an operator.
type validFn func(left, right interface{}) bool
// Function signature for evaluating an operator comparison.
type evalFn func(left, right interface{}) bool
type operatorMeta struct {
valid []validFn
eval evalFn
}
Now that we've defined our types, we need to implement the rules and comparison functions for Equals.
func sameTypes(left, right interface{}) bool {
return reflect.TypeOf(left).Kind() == reflect.TypeOf(right).Kind()
}
func equals(left, right interface{}) bool {
return reflect.DeepEqual(left, right)
}
Awesome! So we can now validate that our two values are of the same type, and we can compare them against each other if they are. The last piece of the puzzle, is mapping the operator to its appropriate rules and evaluation and having a function to execute all of this logic.
var args = map[Operator]operatorMeta{
Equals: {
valid: []validFn{sameTypes},
eval: equals,
},
}
func compare(o Operator, left, right interface{}) (bool, error) {
opArgs, ok := args[o]
if !ok {
// You haven't implemented logic for this operator.
}
for _, validFn := range opArgs.valid {
if !validFn(left, right) {
// One of the rules were not satisfied.
}
}
return opArgs.eval(left, right), nil
}
Let's summarize what we have so far:
Abstracted a basic comparison into a value and operator.
Created a way to validate whether a pair of values are valid for an operator.
Created a way to evaluate an operator, given two values.
(Go Playground)
I hope that I gave some insight into how you can approach this. It's a simple idea, but can take some boilerplate to get working properly.
Good luck!

Check if every item in a struct is unchanged

I have the following package:
// Contains state read in from the command line
type State struct {
Domain string // Domain to check for
DomainList string // File location for a list of domains
OutputNormal string // File to output in normal format
OutputDomains string // File to output domains only to
Verbose bool // Verbose prints, incl. Debug information
Threads int // Number of threads to use
NoColour bool // Strip colour from output
Silent bool // Output domains only
Usage bool // Print usage information
}
func InitState() (state State) {
return State { "", "", "", "", false, 20, false, false, false }
}
func ValidateState(s *State) (result bool, error string ) {
if s.Domain == "" && s.DomainList == "" {
return false, "You must specify either a domain or list of domains to test"
}
return true, ""
}
Within ValidateState() I would like to return true if every item in State is the same as what is defined in InitState(). I can see a few ways to do this, but nothing that seems concise. I would greatly value some direction!
Struct values are comparable if all their fields are comparable (see Spec: Comparison operators). And since in your case this holds, we can take advantage of this.
In your case the simplest and most efficient way to achieve this is to save a struct value holding the initial value, and whenever you want to tell if a struct value (if any of its fields) has changed, simply compare it to the saved, initial value. This is all it takes:
var defaultState = InitState()
func isUnchanged(s State) bool {
return s == defaultState
}
Testing it:
s := InitState()
fmt.Println(isUnchanged(s))
s.Threads = 1
fmt.Println(isUnchanged(s))
Output (try it on the Go Playground):
true
false
Note that this solution will still work without any modification if you change the State type by adding / removing / renaming / rearranging fields as long as they all will still be comparable. As a counter example, if you add a field of slice type, it won't work anymore as slices are not comparable. It will result in a compile-time error. To handle such cases, reflect.DeepEqual() might be used instead of the simple == comparison operator.
Also note that you should create default values of State like this:
func NewState() State {
return State{Threads: 20}
}
You don't have to list fields whose values are the zero values of their types.

Sharing a common value in all enum values

I have the following code where every variant of the enum Message has a Term value associated with it:
type Term = usize;
pub enum Message {
AppendRequest(Term),
AppendResponse(Term),
VoteRequest(Term),
VoteResponse(Term),
}
impl Message {
pub fn term(&self) -> Term {
match *self {
Message::AppendRequest(term) => term,
Message::AppendResponse(term) => term,
Message::VoteRequest(term) => term,
Message::VoteResponse(term) =>term,
}
}
}
I want to, given a Message be able to get its term without having to deconstruct the actual Message value I have. The best I could come up with was creating a public function that unpacked the value for me, but this feels clunky. If I ever add a new enum value, I'm going to have to remember to update match statement in the term function.
Is there a more succinct/ergonomic way to express the code above? Is there some way to say "hey, every value for this enum will have also have a Term value associated with it.
Is there some way to say "hey, every value for this enum will have also have a Term value associated with it.
No. This is usually handled by splitting the enum into two parts, with a struct containing all the common parts:
pub struct Message {
term: Term,
kind: MessageKind,
}
pub enum MessageKind {
AppendRequest,
AppendResponse,
VoteRequest,
VoteResponse,
}
One option is to implement the Deref (and/or DerefMut) trait to convert to the common part.
You still have to update that implementation each time you add to the Enum, but there is less boilerplate at the point of use.
E.g., an example below, note that main accesses the field number on the Enum.
use std::ops::Deref;
use std::string::String;
enum JudgedNumber {
GoodNumber(Number),
BadNumber(Number, String),
}
struct Number { number: i32 }
fn main() {
let nice = JudgedNumber::GoodNumber(Number{number: 42});
let naughty = JudgedNumber::BadNumber(
Number{number: 666}, "Damn you to hell".to_string());
println!("j1 = {}", j1.number);
println!("j2 = {}", j2.number);
}
impl Deref for JudgedNumber {
type Target = Number;
fn deref(&self) -> &Number {
match self {
JudgedNumber::GoodNumber(n) => n,
JudgedNumber::BadNumber(n, _) => n,
}
}
}
I learnt this from https://github.com/rust-embedded/svd/blob/master/src/svd/cluster.rs

Conditional compilation with a if let enum matching which consists of one item

I have the following enum:
pub enum Game {
Match(GameWorker),
#[cfg(feature = "cups")]
Cup(CupWorker),
}
So, this enum consists of one item if cups feature is disabled. The code below with match compiles okay but in place where I use if lets on matching this enum there is a error:
Working match:
fn clear(&mut self, silent: bool) {
match *self {
Game::Match(ref mut gm) => gm.clear(silent),
#[cfg(feature = "cups")]
Game::Cup(ref mut c) => c.clear(silent),
}
}
if let which leads to a compile error:
let m: &mut Game = Game::Match(...);
if let Game::Match(ref mut gamematch) = *m {
// ...
}
Error:
error[E0162]: irrefutable if-let pattern
--> src/game.rs:436:32
|
436 | if let Game::Match(ref mut gamematch) = *m {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ irrefutable pattern
Minimal example
Is there a way to allow such if lets ? I like this construction but somewhy it is not allowed to use it, I don't understand why. As shown above, match construction works okay in the same case. In my personal opinion here should be a silenceable warning instead of error.
if let expects a refutable pattern, similar to how if expects a bool. You can't write if () { something }, even though () is "valid" in some sense. If you had if () {} else { something_else } it would be statically known that the else cannot occur.
Arguably if true { something } is also statically known, but there's a difference: The condition is a bool, which has two values, so even if you statically know the value, the type still offers multiple variants.
With if let it's the same, but you can use user defined types instead of just bool. If your enum has multiple variants, you can't statically decide that the if let is always taken. If the enum has a single variant, you know for a fact that the if condition is always true, so even if you had an else branch, it would not make any sense at all to exist.

Rust: How to specify lifetimes in closure arguments?

I'm writing a parser generator as a project to learn rust, and I'm running into something I can't figure out with lifetimes and closures. Here's my simplified case (sorry it's as complex as it is, but I need to have the custom iterator in the real version and it seems to make a difference in the compiler's behavior):
Playpen link: http://is.gd/rRm2aa
struct MyIter<'stat, T:Iterator<&'stat str>>{
source: T
}
impl<'stat, T:Iterator<&'stat str>> Iterator<&'stat str> for MyIter<'stat, T>{
fn next(&mut self) -> Option<&'stat str>{
self.source.next()
}
}
struct Scanner<'stat,T:Iterator<&'stat str>>{
input: T
}
impl<'main> Scanner<'main, MyIter<'main,::std::str::Graphemes<'main>>>{
fn scan_literal(&'main mut self) -> Option<String>{
let mut token = String::from_str("");
fn get_chunk<'scan_literal,'main>(result:&'scan_literal mut String,
input: &'main mut MyIter<'main,::std::str::Graphemes<'main>>)
-> Option<&'scan_literal mut String>{
Some(input.take_while(|&chr| chr != "\"")
.fold(result, |&mut acc, chr|{
acc.push_str(chr);
&mut acc
}))
}
get_chunk(&mut token,&mut self.input);
println!("token is {}", token);
Some(token)
}
}
fn main(){
let mut scanner = Scanner{input:MyIter{source:"\"foo\"".graphemes(true)}};
scanner.scan_literal();
}
There are two problems I know of here. First, I have to shadow the 'main lifetime in the get_chunk function (I tried using the one in the impl, but the compiler complains that 'main is undefined inside get_chunk). I think it will still work out because the call to get_chunk later will match the 'main from the impl with the 'main from get_chunk, but I'm not sure that's right.
The second problem is that the &mut acc inside the closure needs to have a lifetime of 'scan_literal in order to work like I want it to (accumulating characters until the first " is encountered for this example). I can't add an explicit lifetime to &mut acc though, and the compiler says its lifetime is limited to the closure itself, and thus I can't return the reference to use in the next iteration of fold. I've gotten the function to compile and run in various other ways, but I don't understand what the problem is here.
My main question is: Is there any way to explicitly specify the lifetime of an argument to a closure? If not, is there a better way to accumulate the string using fold without doing multiple copies?
First, about lifetimes. Functions defined inside other functions are static, they are not connected with their outside code in any way. Consequently, their lifetime parameters are completely independent. You don't want to use 'main as a lifetime parameter for get_chunk() because it will shadow the outer 'main lifetime and give nothing but confusion.
Next, about closures. This expression:
|&mut acc, chr| ...
very likely does not what you really think it does. Closure/function arguments allow irrefutable patterns in them, and & have special meaning in patterns. Namely, it dereferences the value it is matched against, and assigns its identifier to this dereferenced value:
let x: int = 10i;
let p: &int = &x;
match p {
&y => println!("{}", y) // prints 10
}
You can think of & in a pattern as an opposite to & in an expression: in an expression it means "take a reference", in a pattern it means "remove the reference".
mut, however, does not belong to & in patterns; it belongs to the identifier and means that the variable with this identifier is mutable, i.e. you should write not
|&mut acc, chr| ...
but
|& mut acc, chr| ...
You may be interested in this RFC which is exactly about this quirk in the language syntax.
It looks like that you want to do a very strange thing, I'm not sure I understand where you're getting at. It is very likely that you are confusing different string kinds. First of all, you should read the official guide which explains ownership and borrowing and when to use them (you may also want to read the unfinished ownership guide; it will soon get into the main documentation tree), and then you should read strings guide.
Anyway, your problem can be solved in much simpler and generic way:
#[deriving(Clone)]
struct MyIter<'s, T: Iterator<&'s str>> {
source: T
}
impl<'s, T: Iterator<&'s str>> Iterator<&'s str> for MyIter<'s, T>{
fn next(&mut self) -> Option<&'s str>{ // '
self.source.next()
}
}
#[deriving(Clone)]
struct Scanner<'s, T: Iterator<&'s str>> {
input: T
}
impl<'m, T: Iterator<&'m str>> Scanner<'m, T> { // '
fn scan_literal(&mut self) -> Option<String>{
fn get_chunk<'a, T: Iterator<&'a str>>(input: T) -> Option<String> {
Some(
input.take_while(|&chr| chr != "\"")
.fold(String::new(), |mut acc, chr| {
acc.push_str(chr);
acc
})
)
}
let token = get_chunk(self.input.by_ref());
println!("token is {}", token);
token
}
}
fn main(){
let mut scanner = Scanner{
input: MyIter {
source: "\"foo\"".graphemes(true)
}
};
scanner.scan_literal();
}
You don't need to pass external references into the closure; you can generate a String directly in fold() operation. I also generified your code and made it more idiomatic.
Note that now impl for Scanner also works with arbitrary iterators returning &str. It is very likely that you want to write this instead of specializing Scanner to work only with MyIter with Graphemes inside it. by_ref() operation turns &mut I where I is an Iterator<T> into J, where J is an Iterator<T>. It allows further chaining of iterators even if you only have a mutable reference to the original iterator.
By the way, your code is also incomplete; it will only return Some("") because the take_while() will stop at the first quote and won't scan further. You should rewrite it to take initial quote into account.

Resources