Rust has pretty much the same arithmetic and logical operators as C++. bool
is
the same in both languages (as are the true
and false
literals). Rust has
similar concepts of integers, unsigned integers, and floats. However the syntax
is a bit different. Rust uses isize
to mean an integer and usize
to mean an
unsigned integer. These types are pointer sized. E.g., on a 32 bit system,
usize
means a 32 bit unsigned integer. Rust also has explicitly sized types
which are u
or i
followed by 8, 16, 32, 64, or 128. So, for example, u8
is
an 8 bit unsigned integer and i32
is a 32 bit signed integer. For floats, Rust
has f32
and f64
.
Numeric literals can take suffixes to indicate their type. If no suffix is given, Rust tries to infer the
type. If it can't infer, it uses i32
or f64
(if there is a decimal point).
Examples:
fn main() {
let x: bool = true;
let x = 34; // type i32
// let x = 2147483648; // error: literal out of range for `i32`
let x = 34isize;
let x = 34usize;
let x = 34u8;
let x = 34i64;
let x = 34f32;
}
As a side note, Rust lets you redefine variables so the above code is legal -
each let
statement creates a new variable x
and hides the previous one. This
is more useful than you might expect due to variables being immutable by
default.
Numeric literals can be given as binary, octal, and hexadecimal, as well as
decimal. Use the 0b
, 0o
, and 0x
prefixes, respectively. You can use an
underscore anywhere in a numeric literal and it will be ignored. E.g,
fn main() {
let x = 12;
let x = 0b1100;
let x = 0o14;
let x = 0xe;
let y = 0b_1100_0011_1011_0001;
}
Rust has chars and strings, but since they are Unicode, they are a bit different from C++. I'm going to postpone talking about them until after I've introduced pointers, references, and vectors (arrays).
Rust does not implicitly coerce numeric types. In general, Rust has much less
implicit coercion and subtyping than C++. Rust uses the as
keyword for
explicit coercions and casting. Any numeric value can be cast to another numeric
type. as
cannot be used to convert from numeric types to boolean types, but
the reverse can be done. E.g.,
fn main() {
let x = 34usize as isize; // cast usize to isize
let x = 10 as f32; // isize to float
let x = 10.45f64 as i8; // float to i8 (loses precision)
let x = 4u8 as u64; // gains precision
let x = 400u16 as u8; // 144, loses precision (and thus changes the value)
println!("`400u16 as u8` gives {}", x);
let x = -3i8 as u8; // 253, signed to unsigned (changes sign)
println!("`-3i8 as u8` gives {}", x);
//let x = 45 as bool; // FAILS! (use 45 != 0 instead)
let x = true as usize; // cast bool to usize (gives a 1)
}
Rust has the following operators:
Type | Operators |
---|---|
Numeric | + , - , * , / , % |
Bitwise | | , & , ^ , << , >> |
Comparison | == , != , > , < , >= , <= |
Short-circuit logical | || , && |
All of these behave as in C++, however, Rust is a bit stricter about the types
the operators can be applied to - the bitwise operators can only be applied to
integers and the logical operators can only be applied to booleans. Rust has the
-
unary operator which negates a number. The !
operator negates a boolean
and inverts every bit on an integer type (equivalent to ~
in C++ in the latter
case). Rust has compound assignment operators as in C++, e.g., +=
, but does
not have increment or decrement operators (e.g., ++
).