Rust function to read the first line of a file, strip leading hashes and whitespace
Clippy returns a helpful suggestion:


warning: returning the result of a let binding from a block.
         Consider returning the expression directly.
         #[warn(let_and_return)] on by default
   |&gt;
   |&gt;     first_line
   |&gt;     ^^^^^^^^^^
note: this expression can be directly returned
   |&gt;
   |&gt;     let first_line = String::from(first_line.trim());
   |&gt;                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


Don't ignore Results by using let _ =! You should always return them or use expect or unwrap.
The loop could be simplified by using take_while:

let last_hash = first_line.chars().take_while(|&amp;c| c == '#').count();

However, treating one character as one byte is a bad idea because strings are UTF-8 encoded. UTF-8 is a variable-length encoding. You can use char_indices instead.
It's slightly more efficient to take a slice of the string, instead of drain and collect here. It avoids one extra allocation.
Change your function to accept any type that implements BufRead; this will allow you to write easier unit tests.
Actually add those unit tests!
There's no need to create a PathBuf, you aren't pushing path components on. You could just make a &amp;Path, but most functions accept any type that can be converted to a Path (AsRef&lt;Path&gt;). &amp;str implements that.
There's no need to take a reference to something being passed to println! or panic!. These macros automatically take a reference.




use std::fs;
use std::io::BufReader;
use std::io::prelude::*;

/// Get the title of a Markdown file.
///
/// Reads the first line of a Markdown file, strips any hashes and
/// leading/trailing whitespace, and returns the title.
fn title_string&lt;R&gt;(mut rdr: R) -&gt; String
    where R: BufRead,
{
    let mut first_line = String::new();

    rdr.read_line(&amp;mut first_line).expect("Unable to read line");

    // Where do the leading hashes stop?
    let last_hash = first_line
        .char_indices()
        .skip_while(|&amp;(_, c)| c == '#')
        .next()
        .map_or(0, |(idx, _)| idx);

    // Trim the leading hashes and any whitespace
    first_line[last_hash..].trim().into()
}

/// Read the first line of the file into `title`.
fn main() {
    let path = "./example.md";

    let file = match fs::File::open(path) {
        Ok(file) =&gt; file,
        Err(_) =&gt; panic!("Unable to read title from {}", path),
    };
    let buffer = BufReader::new(file);

    let title = title_string(buffer);

    println!("The title is '{}'", title);
}

#[cfg(test)]
mod test {
    use super::title_string;

    #[test]
    fn top_level_heading() {
        assert_eq!(title_string(b"# This is a top-level heading".as_ref()),
                   "This is a top-level heading")
    }

    #[test]
    fn second_level_heading() {
        assert_eq!(title_string(b"## This is a second-level heading".as_ref()),
                   "This is a second-level heading");
    }

    #[test]
    fn fourth_level_heading() {
        assert_eq!(title_string(b"#### Let's jump straight to the fourth-level heading".as_ref()),
                   "Let's jump straight to the fourth-level heading");
    }
}


You should also investigate using a real Markdown parser to avoid nasty pitfalls.