Variables/Mutability
- by default, variables are immutable
- make them mutable by adding
mutin front of the variable name
Constants
- not allowed to use
mutwith constants - constants are always immutable
- the type of the constants must be annotated
- constants should be set only to a constant expression, not the result of a value that could only be computed at runtime.
| immutable variable | mutable variable | constants |
|---|---|---|
| let | let mut | const |
Shadowing
- declare a new variable with the same name as a previous variable in the same scope
- we can change the type of the value but reuse the same name.
Shadowing thus spares us from having to come up with different names, such as
spaces_strandspaces_num
Data Types
- Rust is a statically typed language
- The compiler can usually infer what type we want to use based on the value and how we use it.
- Sometimes, we must add a type annotation
- integer types default to
i32. - float types default to
f64.
| Scalar Types | Compound Types |
|---|---|
| integers | tuples |
| floating-point numbers | arrays |
| Booleans | |
| characters |
Integer Types
| Length | Signed | Unsigned |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| 128-bit | i128 | u128 |
| arch | isize | usize |
| Number literals | Example |
|---|---|
| Decimal | 98_222 |
| Hex | 0xff |
| Octal | 0o77 |
| Binary | 0b1111_0000 |
Byte (u8 only) | b'A' |
Floating-Point Types
IEEE-754
| Length | Signed |
|---|---|
| 8-bit | f32 |
| 16-bit | f64 |
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
Numeric Operations
fn main() {
// addition
let sum = 5 + 10;
// subtraction
let difference = 95.5 - 4.3;
// multiplication
let product = 4 * 30;
// division
let quotient = 56.7 / 32.2;
let truncated = -5 / 3; // 结果为 -1
// remainder
let remainder = 43 % 5;
}
The Boolean Type
fn main() {
let t = true;
let f: bool = false; // with explicit type annotation
}
The Character Type
- four bytes
- Accented letters; Chinese, Japanese, and Korean characters; emoji; and zero-width spaces are all valid
charvalues in Rust. - Unicode Scalar Value(from
U+0000toU+D7FFandU+E000toU+10FFFF)
fn main() {
let c = 'z';
let z: char = 'ℤ'; // with explicit type annotation
let heart_eyed_cat = '😻';
}
The Tuple Type
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
let tup = (500, 6.4, 1);
let (x, y, z) = tup
let (mut x, y) = (1, 2);
x += 2;
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
The Array Type
fn main() {
let a = [1, 2, 3, 4, 5];
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [3; 5]; // [3, 3, 3, 3, 3]
let first = a[0];
let second = a[1];
}
Invalid Array Element Access
- resulted in a runtime error at the point of using an invalid value in the indexing operation.
use std::io;
fn main() {
let a = [1, 2, 3, 4, 5];
println!("Please enter an array index.");
let mut index = String::new();
io::stdin()
.read_line(&mut index)
.expect("Failed to read line");
let index: usize = index
.trim()
.parse()
.expect("Index entered was not a number");
let element = a[index];
println!("The value of the element at index {index} is: {element}");
}
Functions
- fn
- snake_case
fn main() {
println!("Hello, world!");
another_function(5);
print_labeled_measurement(5, 'h');
}
fn another_function(x: i32) {
println!("The value of x is: {x}");
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("The measurement is: {value}{unit_label}");
}
Comments
// line comments
fn main() {
// So we’re doing something complicated here, long enough that we need
// multiple lines of comments to do it! Whew! Hopefully, this comment will
// explain what’s going on.
let lucky_number = 7; // I’m feeling lucky today
}
Statements and Expressions
- Calling a function is an expression
- Calling a macro is an expression
- A new scope block created with curly brackets is an expression
fn main() {
let y = {
let x = 3;
x + 1
};
println!("The value of y is: {y}");
}
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
// You can return early from a function by using the return keyword and specifying a value,
// but most functions return the last expression implicitly.
x + 1
}
Control Flow
if Expressions
- Rust will not automatically try to convert non-Boolean types to a Boolean
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
fn main() {
let number = 3;
// error! Rust will **not** automatically try to convert non-Boolean types to a Boolean
if number {
println!("number was three");
}
// right!
if number != 0 {
println!("number was something other than zero");
}
}
fn main() {
let number = 6;
if number % 4 == 0 {
println!("number is divisible by 4");
} else if number % 3 == 0 {
println!("number is divisible by 3");
} else if number % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
Using if in a let Statement
- like ternary operator
fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };
println!("The value of number is: {number}");
}
Repeating Code with loop
fn main() {
loop {
println!("again!");
}
}
Returning Values from Loops
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is {result}");
}
Loop Labels to Disambiguate Between Multiple Loops
fn main() {
let mut count = 0;
'counting_up: loop {
println!("count = {count}");
let mut remaining = 10;
loop {
println!("remaining = {remaining}");
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {count}");
}
Java
public class Main {
public static void main(String[] args) {
int count = 0;
countingUp:
while (true) {
System.out.println("count = " + count);
int remaining = 10;
while (true) {
System.out.println("remaining = " + remaining);
if (remaining == 9) {
break;
}
if (count == 2) {
break countingUp;
}
remaining -= 1;
}
count += 1;
}
System.out.println("End count = " + count);
}
}
C / C++ goto
#include <stdio.h>
int main()
{
int count = 0;
counting_up:
while (1)
{
printf("count = %d\\n", count);
int remaining = 10;
while (1)
{
printf("remaining = %d\\n", remaining);
if (remaining == 9)
{
break;
}
if (count == 2)
{
goto counting_up_end;
}
remaining -= 1;
}
count += 1;
}
counting_up_end:
printf("End count = %d\\n", count);
return 0;
}
#include <iostream>
int main()
{
int count = 0;
counting_up:
while (true)
{
std::cout << "count = " << count << std::endl;
int remaining = 10;
while (true)
{
std::cout << "remaining = " << remaining << std::endl;
if (remaining == 9)
{
break;
}
if (count == 2)
{
goto counting_up_end;
}
remaining -= 1;
}
count += 1;
}
counting_up_end:
std::cout << "End count = " << count << std::endl;
return 0;
}
Conditional Loops with while
fn main() {
let mut number = 3;
while number != 0 {
println!("{number}!");
number -= 1;
}
println!("LIFTOFF!!!");
}
fn main() {
let a = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("the value is: {}", a[index]);
index += 1;
}
}
Looping Through a Collection with for
fn main() {
for number in (1..4).rev() {
println!("{number}!");
}
println!("LIFTOFF!!!");
}
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {element}");
}
}
Matrix
Integer Overflow
256 → u8
in debug mode: cause your program to panic at runtime
in release mode: Rust performs two’s complement wrapping.
// 解决代码中的错误和 `panic`
fn main() {
let v1 = 251_u8 + 8;
let v2 = i8::checked_add(251, 8).unwrap();
println!("{},{}",v1,v2);
}
pattern matching and destructuring
#![allow(unused)]
fn main() {
let (x, y);
(x, ..) = (3, 4);
[.., y] = [1, 2];
}
explicit type conversion
#![allow(unused)]
fn main() {
let x: i32 = 5;
let mut y: u32 = 5;
y = x as u32;
}
float
#![allow(unused)]
fn main() {
let a: f64 = 0.1 + 0.2;
let b = 0.3;
let diff = a - b;
let tolerance = 10.0e-10;
assert!(diff.abs() < tolerance);
}
注意a一定要显式标注f64,否则会报错:can’t call method abs on ambiguous numeric type float
chat to u8
#![allow(unused)]
fn main() {
for c in 'a'..='z' {
println!("{}", c as u8);
}
}
never return function
#![allow(unused)]
fn main() {
fn never_return_fn() -> ! {
unimplemented!()
}
fn never_return_fn() -> ! {
panic!()
}
fn never_return_fn() -> ! {
todo!();
}
fn never_return_fn() -> ! {
loop {
std::thread::sleep(std::time::Duration::from_secs(1))
}
}
}