Idiomatic implementation of the tribonacci sequence in Rust

江枫思渺然 提交于 2019-12-01 13:04:13

问题


I’m new to Rust, but as a fan of Haskell, I greatly appreciate the way match works in Rust. Now I’m faced with the rare case where I do need fall-through – in the sense that I would like all matching cases of several overlapping ones to be executed. This works:

fn options(stairs: i32) -> i32 {
    if stairs == 0 {
        return 1;
    }
    let mut count: i32 = 0;
    if stairs >= 1 {
        count += options(stairs - 1);
    }
    if stairs >= 2 {
        count += options(stairs - 2);
    }
    if stairs >= 3 {
        count += options(stairs - 3);
    }
    count
}

My question is whether this is idiomatic in Rust or whether there is a better way.

The context is a question from Cracking the Coding Interview: “A child is running up a staircase with n steps and can hop either 1 step, 2 steps, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs.”


回答1:


Based on the definition of the tribonacci sequence I found you could write it in a more concise manner like this:

fn options(stairs: i32) -> i32 {
    match stairs {
        0 => 0,
        1 => 1,
        2 => 1,
        3 => 2,
        _ => options(stairs - 1) + options(stairs - 2) + options(stairs - 3)
    }
}

I would also recommend changing the funtion definition to only accept positive integers, e.g. u32.




回答2:


To answer the generic question, I would argue that match and fallthrough are somewhat antithetical.

match is used to be able to perform different actions based on the different patterns. Most of the time, the very values extracted via pattern matching are so different than a fallthrough does not make sense.

A fallthrough, instead, points to a sequence of actions. There are many ways to express sequences: recursion, iteration, ...

In your case, for example, one could use a loop:

for i in 1..4 {
    if stairs >= i {
        count += options(stairs - i);
    }
}

Of course, I find @ljedrz' solution even more elegant in this particular instance.




回答3:


I would advise to avoid recursion in Rust. It is better to use iterators:

struct Trib(usize, usize, usize);

impl Default for Trib {
    fn default() -> Trib {
        Trib(1, 0, 0)
    }
}

impl Iterator for Trib {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        let &mut Trib(a, b, c) = self;
        let d = a + b + c;
        *self = Trib(b, c, d);
        Some(d)
    }
}

fn options(stairs: usize) -> usize {
    Trib::default().take(stairs + 1).last().unwrap()
}

fn main() {
    for (i, v) in Trib::default().enumerate().take(10) {
        println!("i={}, t={}", i, v);
    }

    println!("{}", options(0));
    println!("{}", options(1));
    println!("{}", options(3));
    println!("{}", options(7));
}

Playground



来源:https://stackoverflow.com/questions/42509526/idiomatic-implementation-of-the-tribonacci-sequence-in-rust

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!