Wohoo, we've made it to the halfway point 💪 For those following carefully, it hasn't quite been 15 continuous days, but in sum we've written 15 Rust blogs and learned (and suffered) a bunch. I'm not going to mark this blog with anything special. My only goal right now is to finish the Rust book by day 30. Let's goooo!
Yesterday's questions answered
- A
const
function simply describes a function that is called from with in aconst context
. Aconst context
exists in specific expressions, particularly those linked to array size and length declaration and as well asconst
,static
andenum
declaration.const
functions are called at compile time. - The "use case" for integer overflow seems to be limited to primarily the crypto world. I found an article explaining how to handling for a specific type of smart contract (I didn't really read it, it's too early for smart contracts!!!). Another situation could be in a memory restrictive environment. Imagine a tiny CPU processing requests from sensors in some kind of embedded system. If one of those sensors is faulty or there is a bug in the communication protocol (the latter being unlikely) the CPU could receive a 256 instead of 255, leading to an overflow.
Today's open questions
- What is a
static
?
Fun fun FUNctions
We already covered the basic syntax of functions, particularly in day 3. I'll add some summary points that I've learned to better express how functions work.
Remember, a function in Rust can return a value in Rust by ending in an expression or a return
statement. The Rust book provides useful definitions for those terms:
Statements are instructions that perform some action and do not return a value.
Expressions evaluate to a resultant value
We can see now that the return
keyword offers a unique behaviour for statements in Rust. This also explains why you cannot chain declaration statements in Rust, as a statement does not return a value, for example in Python:
x = y = 6
print(f"{x}, {y}")
# 6, 6
Functions, however, are not the only instance where expressions in an inner scope can be used to return a value to an outer scope in Rust. We've already encountered this a few times:
let x = {
let x = 2;
x + 2
}
println!("x = {x}"); // 4
let y = match johnny_is_awesome {
Ok(johnny) => true,
Err(_) => false
}
println!("Is Johnny awesome? {y}");
We could use a loop
or if
expression in a similar fashion. What's interesting here is that Rust is consistent to the definitions it stated above. And I'd like to shamelessly speculate that the inclusion return
statement may even be a historical product from programming tradition (or to make Rust seem not too try hard hipster).
Quickly on ifs
I'm pretty certain I've been mistakenly calling if
expressions if
statements for the entirety of this blog 🐒 Kudos if you spotted those mistakes. As noted above it's possible for a value to be assigned from an if
expression in Rust. As such (and this is also true for match
expressions), each arm (aka block) of an if expression must yield a result of the same type (only if you care about your code compiling, of course). I'm guessing my confusion stems from the Python world where if
is rarely used as an expression:
args = args if args else {}
if not args:
args = {}
Even quicker on loops
A couple of neat tricks for loops in Rust:
- You can label a loop. This label can be used by the
continue
orbreak
keywords (not specifying the label will break the innermost loop of the current scope). Note the single'
here, it's not a typo:
'outer: loop {
'inner: loop {
if ... {
break 'outer;
} else {
break; // Breaks 'inner
}
}
}
- Range iterators have a
rev
method which will reverse the order of the range!
Top comments (0)