I was interested in Rust, and so I started reading the Rust programming guide on the Rust website, and discovered that variables are declared in the following manner:
let x: i32 = 5;
Which means assign the value integer 5 to the variable type integer 32 bit which shall be referred to by the notation x
from this point onwards.
My main question is why is the let
keyword is there at all? It seems redundant, as if it doesn't actually "do" anything.
I assume the compiler would be able to tell that the following is a variable (or const variable) declaration:
x: i32 = 5;
There doesn't appear to be a reason for a let
keyword, but presumably there is a smart reason because Rust is focused on safety. So what is that reason?
Edit: Addition: As function arguments, the let keyword is not required. Here is an example:
fn add1(x: i32) -> i32
{
x = x + 1
}
This seems a bit strange - this "looks like" a pass by reference because of the missing let
. But it's not. It's a pass by value. (Or at least I think it is.) Is this a syntactic inconsistency?
As an aside, I would find it a lot more logical to change this statement around and write:
i32 x = 5;
Put a colon in there if you will:
i32: x = 5;
I guess I would find that more logical because:
Perhaps some think the other way around? But this brings me to another point; how can one declare a several variables of the same type in Rust? Such as:
let x, y, z: i32 = {4, 5, 5} // A guess of what this might look like?
Or is this just not allowed in Rust?
The primary use for the let keyword is in let statements, which are used to introduce a new set of variables into the current scope, as given by a pattern. The pattern is most commonly a single variable, which means no pattern matching is done and the expression given is bound to the variable.
Rust's closures are anonymous functions you can save in a variable or pass as arguments to other functions. You can create the closure in one place and then call the closure elsewhere to evaluate it in a different context. Unlike functions, closures can capture values from the scope in which they're defined.
Rust closures are harder for three main reasons: The first is that it is both statically and strongly typed, so we'll need to explicitly annotate these function types. Second, Lua functions are dynamically allocated ('boxed'.)
Rust uses a borrow checker to enforce its ownership rules and ensure that programs are memory safe. The ownership rules dictate how Rust manages memory over the stack and heap. As you write Rust programs, you'll need to use variables without changing the ownership of the associated value.
Rust has local type inference, so the type normally doesn’t need to be written; let x = 5;
will suffice. x = 5;
would be quite different, as it would not declare a variable x
, and Rust very deliberately separates declaration and assignment.
It’s also actually let PATTERN = EXPR;
, not just let IDENT = EXPR;
, so removing the let
keyword would cause grammatical ambiguity. A pattern could be mut x
(making the variable binding mutable), it could be (a, b)
signifying tuple unpacking, &c.
You only think i32 x = 5;
makes sense because you’re used to languages like C++. Seriously, who came up with that idea? It makes more sense on purely philosophical grounds to have the type after the name than before, and having just the type to declare variables is silly too. All sorts of grammatical ambiguity there. Type inference, allowing you to omit the type altogether, is a much nicer approach all round.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With