Today we’ll experience a sampler of Rust. I’ll provide links that will get you set up, then you’ll solve the first Project Euler problem in Rust. You’ll see some of the syntax, and learn what a macro is. I hope to show you that the language is robust, easy to use and blindingly fast! It also boasts which we’ll leave for another post but is a huge selling feature. fearless concurrency Why Rust you may ask? It really depends who you are! University armed me with JavaScript and Python, allowing me to pursue web based projects. Recently, I’ve needed to work closer to the metal to achieve quicker code execution. Rust is quite different to the languages mentioned above as it lacks a garbage collector, and is statically typed. If you run into issues, the compiler error messages are usually great enough to act like an expert pair programmer, otherwise the community is welcoming and helpful. Check out these companies using Rust in production. I’ll assume you have some familiarity with executing commands in the terminal or command prompt, and know some programming terminology (like what functions are). Let’s start with the first . The problem wants us to find the sum of all the multiples of 3 or 5 below 1000. Before we even tackle the problem we’ll set up and install Rust. We’ll create a project and discuss the difference between a macro and a function. You’ll see how to write unit tests as well as generate pretty documentation. Finally we’ll solve the problem using a loop, and then functionally with an iterator. It’s gonna be a blast 🚀. Project Euler problem I also made this video which you may like! Installing and Setting up Rust Many people have worked very hard to make the installation process great, so I’ll point to those resources. If you have Rust installed and you enjoy your setup, please feel free to skip this section. Otherwise, let’s get Rust! is a “toolchain installer for the systems programming Rust”. Basically it handles everything for you, and will get you up and running very fast. Go to and follow the instructions for your platform. Rustup https://www.rustup.rs/ Rustup has some nifty features. You can add offline documentation by running the following command . To access your offline rust documentation type: in your terminal or command line. A browser will open with: rustup component add rust-docs rustup doc The Rust Bookshelf API Documentation Extended Error Documentation (for investigating compiler errors) The Rust Bookshelf is fantastic, and is a great place to go for all levels of Rust users. Online link to these resources ! These resources can be life saving when you’re in the wilderness, writing Rust without wifi 🏕️. here lists the code editor support for Rust. As of writing, and have the best support. VSCode is a fantastic free option, and is what I use. Are we (I)DE yet? VSCode IntelliJ IDEA Again there are other posts that cover complete setups. I recommend or . The community is working hard improving the developer experience and these posts may become out of date quite quickly. Searching for the Rust Language Server (RLS) may give more up to date instructions for setting up an IDE. ShaderCat’s post Asquera’s post Of course you can just code in notepad… The compiler is helpful and I respect your decision. Cargo “Cargo is the Rust package manager.” ~ The Cargo Book Cargo is to Rust as NPM is to JavaScript, or pip is to Python, or RubyGems is to Ruby…sort of? Cargo sets up projects, installs dependencies, builds projects, runs tests, generates documentation and uploads your libraries to . This is a perfect time to start working on our Project Euler problem. To check that everything installed properly run in your terminal: crates.io cargo version Your version number does not need to match. Build yourself a new project with the command . cargo new euler_sum --bin Use `cargo help` to learn more This command tells Cargo to set up a new application called “euler_sum” in a new folder. By default cargo creates a library, so we’ve used to tell Rust to create an application (“bin” is short for binary). Use to change your directory into the application folder. This is what you should find: --bin cd euler_sum .├── Cargo.toml└── src└── main.rs 1 directory, 2 files The Cargo.toml file is your projects or metadata. If you’re familiar with JavaScript, it’s similar to the file. You list your dependencies here. More information about it can be found in The Cargo Book , and you can learn about the cargo options with . manifest package.json here cargo help contains a tiny Rust program: main.rs fn main() {println!("Hello, world!");} Run the code with (while in the folder with the Cargo.toml file). cargo run AND ! You’ve run your first Rust program!!!!🎉🎉🎉 STOP CELEBRATE is the way you declare a function. All application projects require a function as an entry to your program. This function has no arguments, and doesn’t return anything. fn main The body of the function contains this word: . This is called a macro. It’s looks like a function but it ends with an . Rust uses macros to do very powerful things, and often libraries use them to be very clever. Let’s quickly learn what makes them different from just a function. println! ! Macro detour Macros allow you to generate code based on patterns! If you need to copy paste code with minor changes, you could write a macro that writes the code for you. When you compile your project, macros are all expanded (written) first, and then the code is compiled as if you’d written what the macros generate. Basically macros write code for you. Let’s have a look at what the macro looks like expanded. Run the following command: println! $ rustc src/main.rs --pretty=expanded -Z unstable-options Here’s my output: “macros write code for you” Notice that has cleverly generated code to print “Hello, world!” to the terminal. Because macros are able to pattern match, different code is generated based on different inputs! Therefore you can use to format strings as well: println! println! println!("Hello, {}!", "lovely humanoid");// prints -> Hello, lovely humanoid! println!("Hello, {name}! Want {thing}?", name="Rust", thing="hugs");// -> Hello, Rust! Want hugs? println!("{num:>0width$}", num=42, width=4);// -> 0042 Another benefit of pattern matching is compiler errors if you muck up the macro’s arguments. If you write , the compiler will helpfully say " " as well as a cool diagram. . println!("{}"); error: 1 positional argument in format string, but no arguments were given You should definitely try it Exercises detour 🤔 What do the macro’s above expand to? The answer may surprise you. More or less code than you expected? println! Investigate more string formatting options (Rust by Example) and (docs). here here Guess and then find out what the below code outputs: println!("{0} {1}'s {0} {1}, no matter how small!", "a", "person"); Writing the tests Because we all want our code test driven as well as type driven, you’re obviously itching to find out how to write tests! All we need here is a simple unit test. If you were writing a library, you could also write doctests. A test is merely a function that you annotate with an attribute. #[test]fn simple_test() {assert_eq!(solution(10), 23);} The attribute tells Rust that this is a testing function. Therefore this function runs when is run. panics if the two arguments aren’t equal, thus failing the test. You can also use which takes only a single argument, checking for the argument to evaluate to . #[test] cargo test assert_eq! assert! true Run the test using . (It should error because we haven’t defined the function yet.) If you want to see the tests pass, replace the with . cargo test solution assert_eq!(solution(10), 23); assert!(true); Generating documentation It’s time to start coding the Project Euler problem. We’ll write the solution in a function called . solution Let’s start with the of the function: type solution pub fn solution(max: u64) -> u64 {unimplemented!} This is a lic function, that takes an argument of type and returns a . A is a numeric type, called an unsigned integer. These are integers that fit into 64 bits that can only be positive. This immediately tells us that we cannot pass negative numbers into this function, and the function will never return a negative number. pub max u64 u64 u64 Just for fun lets generate some documentation. Rust comments can either be the double slash at the start of the line, or . These do not generate documentation. Triple slashes before a declaration do generate documentation: // /* multiline comment */ /// /// `solution` function solves the first Project Euler problempub fn solution(max: u64) -> u64 {// A boring commentunimplemented!()} If you add this code and run the cargo command , your browser will open with freshly generated documentation! The documentation supports markdown, meaning you can add headings and links. ! cargo doc --open Read more about documentation generation here A rough solution to the problem The below code should look slightly familiar to you. Try to understand what’s going on before reading on. We will be making this much simpler, but this is a great starting point. pub fn solution(max: u64) -> u64 {let mut result = 0;let mut i = 0;loop {if i >= max {break;}if i % 3 == 0 || i % 5 == 0 {result += i;}i += 1;}return result;} Most of this should be fairly self explanatory except maybe the . is a way of telling Rust when a variable should be mutable. Here we’re saying that and need to be mutable. Without we would get an error when trying to execute or . Delete and see the error for yourself. In Rust variables are immutable by default, unless explicitly mutable. Rust functions must also explicitly declare if they’re going to be mutating arguments passed in. Function behavior is explicit in the type signature. mut mut result i mut result += i i += 1 mut There are a lot of things we can clean up here. Firstly imperative code is quite verbose. Instead of using the and , we can use a loop over a , like so: loop break for range pub fn solution(max: u64) -> u64 {let mut result = 0;for i in 0..max {if i % 3 == 0 || i % 5 == 0 {result += i;}}return result;} Notice we don’t have to manage the variable anymore. is the range, and the loop iterates over the range. A loop can iterate over any type that implements the trait. We won’t cover traits here, but for now think of it as an interface (although it’s much more). Because the range implements Iterator, you can use iterator methods like , , and . i 0..max for for Iterator map filter fold Filter lets you filter the elements based on a predicate, or a function that returns a boolean. We can thus move the conditionals into a filter to only get the values we want: if i pub fn solution(max: u64) -> u64 {let mut result = 0;for i in (0..max).filter(|n| n % 3 == 0 || n % 5 == 0) {result += i;}return result;} What is this funny syntax? |n| n % 3 == 0 || n % 5 == 0 This is a closure. It’s an anonymous function that can be passed into another function. is the argument/s, and the rest is the function body. The same exact closure can also be written like so (with an explicit function body and statement): |n| return |n| { return n % 3 == 0 || n % 5 == 0;} In Rust, if your statement is on the last line of a function, you can omit the and semicolon to return implicitly. Using that trick we can remove the from our function: return return return pub fn solution(max: u64) -> u64 {let mut result = 0;for i in (0..max).filter(|n| n % 3 == 0 || n % 5 == 0) {result += i;}// Implicit return below:result} There is still one annoying thing. We have a mutable variable hanging around. In a larger program this variable could be mutated elsewhere accidentally, and needs to be managed separately. Summing up the values from the iterator doesn’t require another variable and can be done using iterator methods! You could use the or method. result fold sum pub fn solution(max: u64) -> u64 {(0..max).filter(|n| n % 3 == 0 || n % 5 == 0).sum()} There are many iterator methods and they can sometimes be used solely to solve problems. We could also easily introduce fork-join parallelism with a library such as . Read more about iterators here! Rayon Call your new function from the function and print out your answer. Run the program with . solution main cargo run 🎈Congratulations for completing the first Project Euler question in Rust 🎈. I hope you enjoyed this whirlwind tour! In the future I hope to delve deeper into traits (especially the Iterator trait), macros, concurrency and functional programming. Maybe I’ve convinced you to continue to explore this mind expanding language. Why not continue sampling Rust with Simple Sorting Algorithms in Rust? If you liked the post, please show it with 👏! I love feedback to please leave a comment or message me on Twitter. I also love ideas, so if there is a blog post you wished existed on Rust, I’d be happy to write it for you! Follow me on Twitter: @spyr1014 Thank you for reading! ❤ References Fearless Concurrency- https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html Rustup- https://www.rustup.rs/ VSCode- https://code.visualstudio.com/ Are we (I)DE yet?- https://areweideyet.com/ IntelliJ IDEA- https://intellij-rust.github.io/ Rust documentation link- https://www.rust-lang.org/en-US/documentation.html Rustdoc — https://doc.rust-lang.org/beta/rustdoc/what-is-rustdoc.html The Cargo Book (Cargo.toml)- https://doc.rust-lang.org/cargo/reference/manifest.html Iterators: https://doc.rust-lang.org/std/iter/index.html