Why won't this code work?

I’m quite new to Rust, I wanted to write a really simple Caeser cipher which moves every letter forward by 1 in the alphabet, but I get this error, and I couldn’t figure out the exact cause. I’d appreciate any suggestions about what I’m doing wrong.

use std::io;
fn main(){

    let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    let mut buffer: Vec<char> = Vec::new();

    let mut s = String::new();

    io::stdin().read_line(&mut s)
    .expect("Cannot read input!");

    for _char in s.chars() {
        let index = letters.chars().position(|r| r == _char).unwrap();
        let new_index = index+1 % letters.len();

        buffer.push(letters.chars().nth(new_index).unwrap());
    }

    for _char in buffer.iter() {
        print!("{}", _char);
    }

}

Error: thread ‘main’ panicked at ‘called Option::unwrap() on a None value’

Your input string includes the newline character, which does not exist in letters.
Usually you would just “pass through” any characters that can’t be encoded.

index+1 % letters.len() won’t work properly either, since % binds more tightly than +.

1 Like

Use something like: let s = s.trim(); after reading from stdin, and you must deal with lowercase, punctuation etc. Otherwise it will panick again.

FWIW, treating chars as u8 might simplify this problem as well and keep you from needing that sort of reference string as a lookup table.

Yes, something along these lines:

2 Likes

I love that. Tweaked it a bit to show using a type alias for u8 instead of a struct with a single field.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=42d43127a4e4fc3473f0fd00934323ab

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.