语言技巧

编辑:张汉东


返回多态类型

use rand::{thread_rng, Rng};

/// This is the trait that every die needs to implement to be... well... "rollable", right?
pub trait Rollable {
    /// Roll the die
    fn roll() -> Self;
    /// Get the value from the latest roll
    fn val(&self) -> u8;
}

/// A generic function to roll a given die.
pub fn roll<T: Rollable>() -> T {
    Rollable::roll() // <- Note that here `Rollable` is the current type for a given call!
}

/// A D6 die (6 faces): a roll will give you a `u8` in the `1..=6` range.
#[derive(Debug)]
pub struct D6(u8);

impl Rollable for D6 {
    fn roll() -> D6 {
        D6 {
            0: thread_rng().gen_range(1..=6),
        }
    }
    fn val(&self) -> u8 {
        self.0
    }
}

/// A D8 die (8 faces): a roll will give you a `u8` in the `1..=8` range.
#[derive(Debug)]
pub struct D8(u8);

impl Rollable for D8 {
    fn roll() -> D8 {
        D8 {
            0: thread_rng().gen_range(1..=8),
        }
    }
    fn val(&self) -> u8 {
        self.0
    }
}

#[derive(Debug)]
struct Fake100(u8);

impl Rollable for Fake100 {
    fn roll() -> Fake100 {
        Fake100 { 0: 100 } // <- forces it to roll 100
    }
    fn val(&self) -> u8 {
        self.0
    }
}

fn main() {
    // let's roll a D6
    let r: D6 = roll();
    println!("{:?}", r); // D6(3)

    // let's roll a D8
    let r: D8 = roll();
    println!("{:?}", r); // D8(3)

    println!("I bet I'll get a 100 this time!");
    let d: Fake100 = roll();
    println!("Look what I got: {}!", d.val()) // <- yeah this will always be 100
}

也支持类型推断:

fn try_dodge_attack(d6: D6, d8: D8) -> bool {
    d6.val() + d8.val() > 10
}

fn main() {
    let escaped = try_dodge_attack(roll(), roll());
    println!(
        "{}",
        match escaped {
            true => "You dogded!",
            false => "Ouch! The attack hit you!",
        }
    );
}

来源

一个零开销链表的实现

下面代码实现了一个 持久性/不变性(Persistent / Immutable )的单向链表(Singly-linked)。


#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum List<'a, T> {
    Node { data: T, next: &'a List<'a, T> },
    Tail,
}

impl<T> Default for List<'_, T> {
    fn default() -> Self {
        List::Tail
    }
}

impl<'a, T> List<'a, T> {
    pub fn add(&'a self, data: T) -> Self {
        List::Node { data, next: self }
    }

    pub fn rev_iter(&'a self, f: impl Fn(&'a T)) {
        if let List::Node { data, next } = self {
            next.rev_iter(&f);
            f(data);
        }
    }

    pub fn try_rev_iter<E, F>(&'a self, f: F) -> Result<(), E>
    where
        F: Fn(&'a T) -> Result<(), E>,
    {
        if let List::Node { data, next } = self {
            next.try_rev_iter(&f)?;
            f(data)?;
        }
        Ok(())
    }
}

pub struct ListIter<'a, T>(&'a List<'a, T>);

impl<'a, T> IntoIterator for &'a List<'a, T> {
    type Item = &'a T;

    type IntoIter = ListIter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        ListIter(self)
    }
}

impl<'a, T> Iterator for ListIter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            List::Node { data, next } => {
                self.0 = next;
                Some(data)
            }
            List::Tail => None,
        }
    }
}


#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Num(f64),
    Bool(bool),
    String(String),
}

#[derive(PartialEq)]
pub enum ValueKind {
    Num,
    Bool,
    String,
}

impl Value {
    pub fn kind(&self) -> ValueKind {
        match self {
            Value::Num(_) => ValueKind::Num,
            Value::Bool(_) => ValueKind::Bool,
            Value::String(_) => ValueKind::String,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Expr {
    Value(Value),
    Variable(String),
    UnExpr(UnExprKind, Box<Expr>),
    BinExpr(BinExprKind, Box<(Expr, Expr)>),
    Define(String, Box<(Expr, Expr)>),
    IfThenElse(Box<(Expr, Expr, Expr)>),
}

#[derive(Debug, Copy, Clone)]
pub enum UnExprKind {
    Not,
    Neg,
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum BinExprKind {
    // Arithmetic
    Add,
    Sub,
    Mul,
    Div,

    // Logic
    And,
    Or,
    Equals,
    NotEquals,
}

type Variables<'a> = List<'a, (String, Value)>;

pub fn eval(vars: &Variables<'_>, expr: Expr) -> Option<Value> {
    match expr {
        Expr::Value(val) => Some(val),

        Expr::Variable(var) => vars
            .into_iter()
            .find(|&(v, _)| *v == var)
            .map(|(_, val)| val.clone()),

        Expr::UnExpr(kind, expr) => {
            eval_unary(kind, vars, *expr)
        }

        Expr::BinExpr(kind, exprs) => {
            eval_binary(kind, vars, exprs.0, exprs.1)
        }

        Expr::Define(name, exprs) => {
            let value = eval(vars, exprs.0)?;
            let vars = vars.add((name, value));
            eval(&vars, exprs.1)
        }

        Expr::IfThenElse(exprs) => {
            if let Value::Bool(b) = eval(vars, exprs.0)? {
                eval(vars, if b { exprs.1 } else { exprs.2 })
            } else {
                None
            }
        }
    }
}

fn eval_unary(
    kind: UnExprKind,
    vars: &Variables<'_>,
    expr: Expr,
) -> Option<Value> {
    let val = eval(vars, expr)?;
    match (kind, val) {
        (UnExprKind::Not, Value::Bool(b)) => {
            Some(Value::Bool(!b))
        }
        (UnExprKind::Neg, Value::Num(n)) => Some(Value::Num(-n)),
        _ => None,
    }
}

fn eval_binary(
    kind: BinExprKind,
    vars: &Variables<'_>,
    lhs: Expr,
    rhs: Expr,
) -> Option<Value> {
    let lhs = eval(vars, lhs)?;

    match kind {
        BinExprKind::Add => {
            if let Value::Num(lhs) = lhs {
                if let Value::Num(rhs) = eval(vars, rhs)? {
                    return Some(Value::Num(lhs + rhs));
                }
            }
            None
        }
        BinExprKind::Sub => {
            if let Value::Num(lhs) = lhs {
                if let Value::Num(rhs) = eval(vars, rhs)? {
                    return Some(Value::Num(lhs - rhs));
                }
            }
            None
        }
        BinExprKind::Mul => {
            if let Value::Num(lhs) = lhs {
                if let Value::Num(rhs) = eval(vars, rhs)? {
                    return Some(Value::Num(lhs * rhs));
                }
            }
            None
        }
        BinExprKind::Div => {
            if let Value::Num(lhs) = lhs {
                if let Value::Num(rhs) = eval(vars, rhs)? {
                    return Some(Value::Num(lhs / rhs));
                }
            }
            None
        }

        BinExprKind::And => {
            if let Value::Bool(lhs) = lhs {
                if !lhs {
                    return Some(Value::Bool(false));
                }
                if let Value::Bool(rhs) = eval(vars, rhs)? {
                    return Some(Value::Bool(rhs));
                }
            }
            None
        }
        BinExprKind::Or => {
            if let Value::Bool(lhs) = lhs {
                if lhs {
                    return Some(Value::Bool(true));
                }
                if let Value::Bool(rhs) = eval(vars, rhs)? {
                    return Some(Value::Bool(rhs));
                }
            }
            None
        }
        BinExprKind::Equals => {
            let rhs = eval(vars, rhs)?;
            if lhs.kind() == rhs.kind() {
                Some(Value::Bool(lhs == rhs))
            } else {
                None
            }
        }
        BinExprKind::NotEquals => {
            let rhs = eval(vars, rhs)?;
            if lhs.kind() == rhs.kind() {
                Some(Value::Bool(lhs != rhs))
            } else {
                None
            }
        }
    }
}
}

来源