Algebraic type system in rust is great

46 points piotr1215

Rust has a powerful algebraic type system, it is easy to construct rich domains. Here is a simplistic example of a card payment domain.

This feature is really similar to F# which I really liked.

Playground link

#![allow(unused)]
type CheckNumber = u32;
type CardNumber = String;

enum CardType {
    Visa,
    Mastercard,
}

#[derive(Debug)]
struct CreditInfo(CheckNumber, CardNumber);

#[derive(Debug)]
enum PaymentMethod {
    Cash,
    Check(CheckNumber),
    Card(CreditInfo),
}

type PaymentAmount = f32;
#[derive(Debug)]
enum Currency {
    Eur,
    Usd,
}

#[derive(Debug)]
struct Payment {
    amount: PaymentAmount,
    currency: Currency,
    method: PaymentMethod,
}

trait PrintDetails {
    fn payment_info(&self) -> String;
}

impl PrintDetails for Payment {
    fn payment_info(&self) -> String {
        let method = match &self.method {
            PaymentMethod::Cash => String::from("cash"),
            PaymentMethod::Check(c) => format!("a check with number {:?}", c),
            PaymentMethod::Card(c) => format!("a check {} with a credit card {}", c.0, c.1),
        };

        format!(
            "An amount of {}, was paid in {:?}, using {}",
            &self.amount, &self.currency, method
        )
    }
}

fn main() {
    let cc_payment = Payment {
        amount: 100.33,
        currency: Currency::Usd,
        method: PaymentMethod::Card(CreditInfo(122, String::from("452389798712097"))),
    };

    let check_payment = Payment {
        amount: 0.33,
        currency: Currency::Eur,
        method: PaymentMethod::Check(42),
    };

    println!("Payment details \
 {}", check_payment.payment_info());
    println!("Payment details \
 {}", cc_payment.payment_info());
}

Results:

Payment details 
 An amount of 0.33, was paid in Eur, using a check with number 42
Payment details 
 An amount of 100.33, was paid in Usd, using a check 122 with a credit card 452389798712097