Some and None, what are they?

2019-03-17 04:02发布

问题:

While programming some small beginner exercises trying to get used to Rust, 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?

回答1:

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.

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.



回答2:

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

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.



回答3:

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.



标签: rust