I think some expansion on the points other people are making here is warranted:
First, unlike Java, Rust doesn't have a compiler-supported constructor method - we create a function fn new
by convention, which acts as a constructor, but it isn't special, the way it is in Java. As @Michael-F-Bryan points out, this is because Rust doesn't have inheritance, and so we don't need to construct any superclass' fields or method tables - there aren't any to construct! As Michael says, the Person { [...] }
syntax is the construction syntax in Rust - it's the 'special' syntax the compiler understands.
The reasons we don't use that syntax everywhere are: it isn't able to enforce more invariants (like an age restriction) than the types of the fields, and it exposes the implementation details of the struct. Fortunately, if the struct's fields aren't public (indicated in rust with pub
), then outside of the module (sorta like a Java namespace), the fields won't be visible, and so it will be impossible to use the construction syntax to fill them in.
Second, the other key point to understand is that in Rust, creating a struct does not imply an allocation of memory on the heap; unlike Java, all structs are created on the stack by default, and you have to put them on the heap yourself (usually with a standard library type like Box
, Rc
, or for a collection, Vec
). This means creating and destroying objects is usually faster, but it's important to figure out over time what is large enough to be 'worth' putting on the heap, or when it's necessary for other reasons. Fortunately, the compiler has error messages that are pretty helpful with this!
Lastly, I wanted to clarify - Java only has signed integer types; byte
for 8-bit, short
for 16-bit, int
for 32-bit, long
for 64-bit. Those types are spelled i8
,i16
, i32
, and i64
in Rust; we also have unsigned integer types, that only include non-negative numbers (but of twice the size), which are u8
, u16
, u32
, and u64
. There are also the larger, less-common i128
and u128
, and there are usize
and isize
, which are used for indexing collections, and are the size of a pointer on that system.
I mention all this because as someone pointed out above, if you're using the uXX
types, a negative number is impossible - the compiler will not compile it as a constant, and if you subtract a larger number from a smaller one, in debug, the program will panic, and in release the program will underflow (and you'll have a huge, positive number).
Hopefully this helps!
Welcome to the community!