What are Some and None?

RustOptional

Rust Problem Overview


I came across some output I don't understand using Vec::get. Here's the code:

fn main() {
    let command = [('G', 'H'), ('H', '5')];

    for i in 0..3 {
        print!(" {} ", i);
        println!("{:?}", command.get(i));
    }
}

the output is

 0 Some(('G', 'H'))
 1 Some(('H', '5'))
 2 None

I've dabbled in Haskell before, and by that I mean looked at a tutorial site for 10 minutes and ran back to C++, but I remember reading something about Some and None for Haskell. I was surprised to see this here in Rust. Could someone explain why .get() returns Some or None?

Rust Solutions


Solution 1 - Rust

The signature of get (for slices, not Vec, since you're using an array/slice) is

fn get(&self, index: usize) -> Option<&T>

That is, it returns an Option, which is an enum defined like

pub enum Option<T> {
    None,
    Some(T),
}

None and Some are the variants of the enum, that is, a value with type Option<T> can either be a None, or it can be a Some containing a value of type T. You can create the Option enum using the variants as well:

let foo = Some(42);
let bar = None;

This is the same as the core data Maybe a = Nothing | Just a type in Haskell; both represent an optional value, it's either there (Some/Just), or it's not (None/Nothing).

These types are often used to represent failure when there's only one possibility for why something failed, for example, .get uses Option to give type-safe bounds-checked array access: it returns None (i.e. no data) when the index is out of bounds, otherwise it returns a Some containing the requested pointer.

See also:

Solution 2 - Rust

command is not a vector (type Vec<T>), it is a fixed-size array (type [(char, char); 2] in your case), and arrays are automatically borrowed into slices (views into arrays), hence you can use all methods defined on slices, including get:

> Returns the element of a slice at the given index, or None if the index is out of bounds.

The behavior is pretty obvious: when given index is valid, it returns Some with the element under that index, otherwise it returns None.

There is another way to access elements in a slice - the indexing operator, which should be familiar to you:

let nums = [1, 2, 3];
let x = nums[1];

It returns the element of the slice directly, but it will fail the current task if the index is out of bounds:

fn main() {
    let x = [1, 2];
    for i in 0..3 {
        println!("{}", x[i]);
    }
}

This program fails:

% ./main2
1
2
task '<main>' failed at 'index out of bounds: the len is 2 but the index is 2', main2.rs:4

The get() method is needed for convenience; it saves you from checking in advance if the given index is valid.

If you don't know what Some and None really are and why they are needed in general, you should read the official tutorial, it explains it because it is very basic concept.

Solution 3 - Rust

Think of Some and None as the canonical "safe" way of working around the fact that the Rust language does not support "safe" use of NULL pointers. Since the length of your Vec is 3, and you have only specified two pairs, the third pair is effectively NULL; instead of returning NULL, it returns None.

Rust provides safety guarantees by forcing us at compile-time, via Some / None, to always deal with the possibility of None being returned.

Solution 4 - Rust

The other answers discussing the return type for get() being option enum are accurate, but I think what is helpful is how to remove the some from the prints. To do that a quick way is to just call the unwrap on the option, although this is not production recommended. For a discussion on option take a look at the rust book here.

Updated with unwrap code in playground (below)

fn main() {
    let command = [('G', 'H'), ('H', '5')];

    for i in 0..3 {
        print!(" {} ", i);
        println!("{:?}", command.get(i).unwrap());
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSyntactic FructoseView Question on Stackoverflow
Solution 1 - RusthuonView Answer on Stackoverflow
Solution 2 - RustVladimir MatveevView Answer on Stackoverflow
Solution 3 - RustJohn HinrichsenView Answer on Stackoverflow
Solution 4 - RustJohn DrinaneView Answer on Stackoverflow