Spelling a word with chemical elements in Rust
Overall


Don't explicitly import Vec or Option, they are part of the prelude.
Basically always want to implement Debug on any type.
I see two types that aren't there: something that holds the elements, something that contains results.
This allows you to implement Display for Spelling. This is more flexible and participates in the ecosystem better.


read_elements


No need to use Path explicitly, &amp;str implements AsRef&lt;Path&gt;.
Can collect iterator of tuples into a HashMap, no need to muck about with a mutable variable.
Don't use unwrap. Prefer expect or return a Result. expect has words that will help you or the user find the problem. Note that we can collect into a Result.
Don't hardcode the filename inside the function.


spell_word


Should not take elem_map by value. Take a reference as we aren't making use of the allocated data.
I'd split the string and just track the string pieces, not the distance into the string.
No explicit return at the end of function.
Return references to the element instead of cloning.


show_result


Don't specify the types on a variable binding; let inference take care of it.
Don't take ownership of Vec, instead take a slice.
I'd avoid allocating in the printing function. I used Itertools to help with the comma separating.


main


Don't specify the type of a collection, let inference take care of it (let foo: Vec&lt;_&gt; = bar.collect()).
Don't check for the argument and then implicitly check again (via indexing). A match or unwrap would be better.
No need to collect into a vector. Instead, skip the program name and just iterate over all the arguments - bonus feature!
No need to explicitly convert String to &amp;str, a &amp;String can be coerced to a &amp;str.
Use raw strings to avoid escaping quotes




extern crate csv;
extern crate itertools;

use std::{env, fmt};
use std::collections::HashMap;

use itertools::Itertools;

type Error = Box&lt;std::error::Error&gt;;

#[derive(Debug, Clone)]
struct Element {
    number: u16,
    symbol: String,
    name: String
}

impl Element {
    fn new (number: u16, symbol: &amp;str, name: &amp;str) -&gt; Element {
        Element {
            number: number,
            symbol: symbol.to_string(),
            name: name.to_string()
        }
    }
}

struct Elements {
    elem_map: HashMap&lt;String, Element&gt;
}

impl Elements {
    fn read_from_file(name: &amp;str) -&gt; Result&lt;Self, Error&gt; {
        let mut csv_reader = csv::Reader::from_file(name)?;

        let elem_map: Result&lt;_, Error&gt; = csv_reader.decode().map(|record| {
            let (number, symbol, name): (u16, String, String) = record?;
            let symbol = symbol.trim();
            let name = name.trim();
            Ok((symbol.to_lowercase().to_string(), Element::new(number, symbol, name)))
        }).collect();

        Ok(Elements { elem_map: elem_map? })
    }

    // Try to spell target_word using elements from elem_map
    fn spell_word(&amp;self, target_word: &amp;str) -&gt; Option&lt;Spelling&gt; {
        let mut result = Vec::new();
        let target_word = target_word.to_lowercase().to_string();
        let mut target_word = target_word.as_str();

        while !target_word.is_empty() {
            // Try matching the next two letters first
            if target_word.len() &gt;= 2 {
                let (head, tail) = target_word.split_at(2);

                if let Some(elem) = self.elem_map.get(head) {
                    result.push(elem);
                    target_word = tail;
                    continue;
                }
            }

            // Try matching one letter if two letters failed
            let (head, tail) = target_word.split_at(1);

            if let Some(elem) = self.elem_map.get(head) {
                result.push(elem);
                target_word = tail;
                continue
            }

            // If no one letter element could be found,
            // this word cannot be spelled using elements
            return None;
        }

        Some(Spelling(result))
    }
}

struct Spelling&lt;'a&gt;(Vec&lt;&amp;'a Element&gt;);

impl&lt;'a&gt; fmt::Display for Spelling&lt;'a&gt; {
    fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result {
        for elem in &amp;self.0 {
            write!(f, "{}", elem.symbol)?;
        }

        write!(f, " (")?;

        for elem in self.0.iter().map(|e| e.name.as_str()).intersperse(", ") {
            write!(f, "{}", elem)?;
        }

        write!(f, ")")
    }
}

fn main() {
    let elements = Elements::read_from_file("./elements.csv").expect("Unable to read elements");

    for target_word in env::args().skip(1) {
        match elements.spell_word(&amp;target_word) {
            Some(spelling) =&gt; println!("{}", spelling),
            None =&gt; println!(r#"Could not find a match for word "{}"."#, target_word)
        }
    }
}