Make your Rust code more DRY

InstructorPascal Precht

Share this video with your friends

Send Tweet

This lesson takes an existing function with duplicated functionality and makes it more DRY by extracting core functionalities into another function.

J. Matthew
~ a year ago

Interesting, so I see the return keyword can be implied at the end of a function (or block?), as demonstrated in read_user_input. I guess that's been true in the sum function as well.

I noticed you changed the Ok function from Ok(val) => { digit = val; } to Ok(val) => digit = val,; I also noticed that the trailing comma wasn't required in the first instance but appears to be in the second. What are the rules for this stuff? I'm guessing these are yet more signals to the compiler (and that it's similar to ES6 JavaScript in that you can dispense with the curly braces when using its fat arrow and only returning a single statement, e.g. const myFunc = (a, b) => a + b).

Thanks for the great course! Looking forward to more guidance on Rust.

Pascal Prechtinstructor
~ a year ago

Hey Matt,

Interesting, so I see the return keyword can be implied at the end of a function (or block?), as demonstrated in read_user_input. I guess that's been true in the sum function as well.

So the rule is:

Every line inside a function that ends with a ; is a statement and if it's the last line of a function body and it doesn't end with a ; it'll return the value of that line's expression.

So yes:

fn sum(a: i32, b: i32) -> i32 {
  a + b
}

^ Therefore returns whatever that last line in the function body evaluates to. However, it's still possible to use explicit return statements, in fact it's needed if you want to return earlier inside a function body.

similar to ES6 JavaScript in that you can dispense with the curly braces when using its fat arrow and only returning a single statement, e.g. const myFunc = (a, b) => a + b).

This is correct. A match branch that is a single-line statement/expression can be written as:

Ok(val) => { some_expr }

Or

Ok(val) => some_expr

Generally, I'd recommend to use as little symbols/characters to express the same thing as possible unless readability suffers from it.

Colin Maroney
~ 11 months ago

i'm curious as to why you can pass a and b to sum but it doesn't move them like the other function did, so that you're still able to pass a and b into println!() without them being & references.

Colin Maroney
~ 11 months ago

i'm also curious as to why you have to say "Pascal".to_string() when assigning the name....is "Pascal" by itself not a string already?

Pascal Prechtinstructor
~ 11 months ago

Hey Colin!

i'm curious as to why you can pass a and b to sum but it doesn't move them like the other function did, so that you're still able to pass a and b into println!() without them being & references.

Excellent question. So the reason there's actually no move happening is because... Rust will only not move values that are either a) primitives that don't require heap allocation (e.g. numbers, those just end up on the stack) or b) types that implement the Copy trait.

i'm also curious as to why you have to say "Pascal".to_string() when assigning the name....is "Pascal" by itself not a string already?

Not exactly. In Rust there can be values of type String, &String, &str and then there's also str, but the last one is usually only accessible via a reference (so &str).

I didn't want to go into that in this lesson because it'll require better understanding of how Rust manages memory as well as ownershiip.

I wrote an article to explain this for now: https://blog.thoughtram.io/string-vs-str-in-rust/