Enums

If you want to specify a Type which can be one of n types then enum can be used. It can be as simple as C enum which can be used to represent choices or can be as powerful as Algebraic Data Types found in Haskell. Enums are called Sum types because at any point the value is one of them n types.

Example 1: Unit-only enum

Simple enum to represent choices from rust-bitcoin

// At any point in time a user can connect using one of the network modes
enum Network {
    Bitcoin,
    Testnet,
    Signet,
    Regtest,
}

So the Network type can be one of the 4 variants.

let bitcoin: Network = Network::Bitcoin;
let testnet: Network = Network::TestNet;
/// other variants

Complex enums where some of the variants can be arbitrary

The semantics are described below,

enum Example<T> {
    Constructor1(T),
    Constructor2(u32),
    Variant1,
    Variant2,
    Constructor3(String),
}

The value of type Example can be one of the two variants or can be created using one of the three constructors by supplying appropriate values.

Option

It is used to denote the presence or absence of a value. When the computation is well defined for a given input then that outcome can be represented using Option::Some(value). Sometimes the result of a computation may not be defined for certain inputs, in that case Option::None is used to denote the absence of the value.

In some cases the value is not known at compile time but can be loaded when the program starts, in that case Option can be used along with mutable variable like shown below,

In other programming languages the commonly used trick is null pointers in combination with run time exceptions which are hard to debug and read.

Result

Some computation may result in a failure. For example you are trying to connect to a bitcoin node with rpc and you failed to provide correct username or password, this is an error not an absence of value. In that case Result is used.

That's why the return type of Client::new(url, Auth::user(username, password)) of RpcApi trait in rust-bitcoincore_rpc module is a result, refer.

In general some computations can fail due to many factors, this can be seen in bitcoincore_rpc crate's Error type,

refer doc.

Accessing Enum Values

There are different ways to work with an enum variant and access its inner value. Consider the following modified example from the documentation for the Read trait. You can also experiment with this on Rust playground.

b.read will return a Result which will wrap a usize for the Ok variant. One way to access this inner value is to append the question mark operator. This will unwrap the inner value, which is the usize representing the bytes successfully read. If the result is an Error variant, this will instead propagate that error to the calling function and then exit the function.

Let's explore triggering an error using the read_exact method. This will read an exact amount of bytes. So if the buffer is too large for the bytes available to read, this will propagate an error (Rust playground):

Run this and see what happens. Then, try modifying the string to make it longer. For example, you can change the first line to let mut b = "This longer string will be read".as_bytes(). See how this changes the result.

Another way to write this could be something like the following (Rust playground):

Further reading

Last updated