Menu

Anagrams Part 16: Rust

March 26, 2023 - Programming, Rust

This is part of a occasionally updated series on various programming languages. It should not be interpreted as a benchmark, but rather as a casual look at various programming languages and how they might be used by somebody for a practical purpose.
Currently, there are Articles written regarding Python,C#, Java and VB6 (merged for some reason),Scala,F# & Ruby,Perl, Delphi, PHP,C++,Haskell,D, VB.NET, QuickBASIC, and Rust

Making a return to my long dormant “Anagrams” series, with a language for which I had actually made a half-hearted attempt at before, Rust

Since I literally never wrote Rust code before this program, I don’t think any sort of performance review would be particularly helpful; I will include that information, regardless, however it should be considered that it is unlikely a seasoned Rust developer could not make it run much better with their wider knowledge base about the language.

First, what is Rust? And yes, this is the equivalent part to recipe articles that blabber about how their grandmother made some recipe when they were a kid and stuff, but you can always scroll down if you don’t want to listen to this copy that I’ve added to make this post a bit better than just “here’s some Rust code, deal with it”.

The Oxford English dictionary defines rust as “a reddish- or yellowish-brown flaky coating of iron oxide that is formed on iron or steel by oxidation, especially in the presence of moisture.”. That’s not relevant here but smartypants people always put definitions when they write.

Rust is a programming language designed for systems-level programming as well as high-level programming. In some ways, that aspect reminds me of D. However, the language is also designed with much stricter capabilities with regards to type checking and even ownership of variables; That aspect is designed to prevent bugs before they happen.

My implementation of the anagrams program reads the dictionary file from a hard-coded location and performs it’s processing. I struggled a bit with the idea of mutable and immutable values as well as “borrowing”; I’m not entirely convinced this program is “correct” in the sense that it is using those concepts correctly, but it has the desired output so it “counts” as part of the anagrams series, I say.

use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
use std::iter::Iterator;
use std::iter::FromIterator;
use std::ops::Not;
fn main() {
    let mut anagram : HashMap<String,Vec<String>> = HashMap::new();
	if let Ok(lines) = read_lines("D:\\textfiles\\dict.txt") {
        for line in lines {
            if let Ok(word) = line {

				let s_slice: &str = &word[..];

				let mut chars: Vec<char> = s_slice.chars().collect();
			    chars.sort_by(|a, b| b.cmp(a));
			    let s = String::from_iter(chars);
                if anagram.contains_key(&s).not() {
                    anagram.insert(s.clone(),vec![]);
                }
                let gramlist = anagram.get_mut(&s);
                gramlist.expect("reason").push(word.clone());

            }
        }
		//print out the results.
        for (key,value) in anagram {
            if value.len() > 1 {
                println!("{}",value.join(","));
            }
        }
    }
}

fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())</pre>
}

Unfortunately I now have to admit that I wrote this a few months ago, which makes it hard to describe what it does. Rust has a lot of unique syntax elements. This provides a lot of expressability but at the cost of being a bit overwhelming. The implementation here really is more or less the same as other examples: There is a HashMap that indexes a vector of strings using a string as a key. By sorting each word, we get the key to which the word should be added, in that way we find anagrams by reviewing all elements where the list has more than one item.

Rust’s mutability and “borrowing” as well as variable ownership mechanics presented issues while I was putting this together. It definitely takes some getting used to, but I can see the benefits that such a design can provide; it results in compile errors instead of mysterious hard-to-trace issues at run-time for certain kinds of safety problems. That’s pretty much what the language was built for, so that tracks.

Have something to say about this post? Comment!