
Learning Rust, Part 5 - rogual
http://foon.uk/rust.html#5
======
jroesch
A comment/correction `io` _is_ stable, its just `chars` directly on a type
that implements `Read` that is still unstable, the majority of `std::io` is
stable these days.

~~~
rogual
Thanks for the clarification. What's the idiomatic way to read one character
from stdin?

~~~
masklinn
The `bytes()` iterator is stable and provides a stream of u8 (well
io::Result<u8>) which is sufficient for what you want. I don't think there's a
good way to decode an iterator of bytes (which bytes isn't either way, but it
could be adapted) to a chars iterator at the moment.

~~~
rogual
Thank you. Bytes will do just fine. I'm glad Rust is pedantic about bytes vs.
chars.

~~~
steveklabnik
To elaborate slightly further, char in Rust is four bytes, as it represents a
Unicode Scalar Value. So the chars iterator isn't yet stable because it's not
clear what should be done in the case of a read of a partial char. This is, of
course, fixable, there's just a lot to do, and that's the question for this
specific API.

------
rogual
With interesting things happening in Rust-land, I decided to take another run
at Rust and see how it's improved in the last year.

This isn't really a blog or a tutorial, it's just me stumbling around and
trying stuff. I enjoy reading this sort of thing when other people do it, so I
hope you get something out of it too.

Previously:
[https://news.ycombinator.com/item?id=8546546](https://news.ycombinator.com/item?id=8546546)

------
masklinn
> When the Rust people say “always use the nightlies”, they mean ALWAYS use
> the nightlies.

AFAIK, the Rust people haven't said that for quite some time. There are still
a number of unstable area (the most annoying to me being benchmarking) but by
and large stable is very much usable.

In your case, the code could be simplified (and would work on stable) by using
a bytes iterator (and an actual for loop):

    
    
        fn main() {
            let mut state = mkstate();
            for it in stdin().bytes() {
                update(&mut state, it.unwrap());
                draw(&state);
            }
        }
    

replace a few `char` by `u8` and change key_dir to:

    
    
        match input {
            b'h' => Coord(-1, 0),
            b'j' => Coord(0, 1),
            b'k' => Coord(0, -1),
            b'l' => Coord(1, 0),
            _ => Coord(0, 0)
        }
    

(I used unwrap because the stdin errors are not handled anyway, might as well
panic)

edit: conventionally, when structures aren't "raw" they're initialised via a
`new()` method, so `mkstate` would usually be `impl State { fn new() -> State
{ … } }`.

And derive(Default) is necessary because, well, you're using default values
for your structs. From what I've seen that's mostly done when partial
overrides of default value makes sense (`Struct { f: v, ..Default::default()
}` will fill any value which isn't provided by whatever's in `Default`) which
isn't the case here.

You could get rid of it by implementing initialisations explicitly, something
along the lines of:

    
    
        impl State {
            fn new() -> State {
                let mut state = State {
                    // or add a new() on them as well
                    position: position::State { objects: Vec::new() },
                    graphics: graphics::State { objects: Vec::new() }
                };
                
                mktest(&mut state, 42, Coord(1, 1), '@');
                mktest(&mut state, 57, Coord(8, 8), '$');
    
                state
            }
        }
    

I'd also suggest deriving Copy on Coord (makes the structure "pass by copy"
rather than "pass by move", so you don't have to clone it explicitly).

And you could `impl Add for Coord` to replace `vadd(old_position, dir)` by
`old_position + dir`

(I believe Rust code also tends to use more methods, but I'm guessing you like
free functions).

You could also replace the inner State structs by type aliases, the struct
doesn't seem to have much value, so

    
    
        mod graphics {
            pub struct State {
                pub objects: Vec<Sprite>
            }
        }
    

=>

    
    
        mod graphics {
            pub type State = Vec<Sprite>
        }
    

and remove the indirections through `objects` (and you get a "free new" on
graphics::State and position::State as they're now just aliases for Vec<_>)

------
zimbatm
Small errata:

    
    
        fn process(state: &State)
    

still has a recursive call after it's been converted to use a loop.

