Rust语法 Flashcards
打印的函数
print!()和println!()
注意放在main中
println!(“Color: ({}, {}, {})”, color.r, color.g, color.b);
rust unit type
类型是()
唯一的值:()
显示返回和隐式返回
return x+y;
x + y
函数式样
fn functionname(parameter1:type, parameter2:type) -> return_type{
}
声明可变变量/声明不可变变量
rust想改变真正改变值的引用需要用?
let &mut x = 3;有问题吗,为什么?有问题的话怎么改。
let x = 3; //不可变
let mut x = 3; //可变
需要用&mut
&mut x 表示 x 是一个可变的引用,但 3
是一个整数(i32类型的字面量),它并不是一个变量的地址,无法为其创建可变引用。
Rust 需要 &mut绑定到一个可变的变量,而不是字面量。
比如:
let mut x =3;
let y = &mut x;
*y = 5;
println!(“{}”, x)
rust的内置函数类型:
有符号整数
无符号整数
浮点数类型
字符类型
字符串类型
C风格数组的创建
整数类型
有符号整数(i8 ~ i128):i8, i16, i32
, i64
, i128
- 无符号整数(u8
~ u128
):u8
, u16
, u32
, u64
, u128
浮点数类型
-
f32
(32 位浮点数) -
f64
(64 位浮点数,默认)
字符类型
-
char
**:Rust 的字符类型,存储 Unicode 字符(不像 C 那样存储 ASCII)。
字符串类型
- &str(字符串切片,C 语言风格的字符串)
- String(对象字符串,类似 Java 的 `String)
let arr: [i32; 3] = [1, 2, 3];
C-like Arrays: [[TypeName]; [length]]
rust类型可以随意更改嘛,可以不规定rust的数据类型嘛,比如let a = 42;
不可以,它是强类型。可以不规定,它会自动推导。
fn swap(x:i32, y:i32) {
let t = y;
y = x;
x = t
}
这是按值传递pass by value,按值传递说明什么?有两个方法可以改,怎么改?
按值传递=传递副本
pass by value说明x和y的值不会影响外部变量。x和y被复制 (按值传递) ,因此此函数不会交换原始变量。
1. 用按引用传递的方式
用&mut符号和解引用
int swap(x: &mut i32, y:&mut32){
let t = *x;
*y = *x;
*x = t
}
2. 用返回值的方法
fn swap(x: i32, y: i32) -> (i32, i32) {(y, x)}
fn main() {
let a = 5;
let b = 10;
let (a, b) = swap(a, b); println!("a = {}, b = {}", a, b);
fn modify_value(x: i32) {
x = 100;
}
fn main() {
let mut num = 5;
modify_value(num);
}
结果是什么?
为什么会发生这样的现象
注意函数里的参数没有声明可变,要声明改成fn modify_value(mut x: i32) ,但即使用了mut也不允许跨函数修改变量。变量传递时会复制,修改不会影响原变量。
fn modify_value(x: i32) {
x = 100; // ❌ 报错,x 不是可变的
}
fn main() {
let mut num = 5;
modify_value(num); // ❌ 这里 num
只是传值,函数内的修改不会影响原变量
}
fn modify_value(mut x: i32) {
x = 100;
}
fn main() {
let mut num = 5;
modify_value(num);
print!(“{}”, num)
}
// 这个会输出什么?为什么
- 在
main
函数中,num
被定义为let mut num = 5;
,意味着它是一个可变变量。 - 然后
modify_value(num);
被调用,把num
的值传递给modify_value
函数。 - 但是,
modify_value(mut x: i32)
只是对x
进行了修改,而 ==x
只是num
的拷贝(Rust 的i32
类型默认是按值传递,而不是引用)。== -
modify_value
内部的x = 100;
只是修改了x
的拷贝,而num
并没有被改变。 - 所以,
print!("{}", num);
依然输出5
。(虽然不会报错)
fn modify_value(x: i32) {
x = 100;
}
fn main() {
let mut num = 5;
modify_value(num);
}
怎么改能够让num=100
fn modify_value(x: &mut i32) {
*x = 100;
}
fn main() {
let mut num = 5;
modify_value(&mut num);
print!(“{}”, num)
}
fn main() {
let mut x = 10;
let r1 = &mut x; let r2 = &mut x; println!("{}", r1); } 有什么问题,如果非要有r1和r2该怎么改
在同一作用域内,不能同时存在多个可变引用(&mut),以防止数据竞争(data race)。
fn main() {
let mut x = 10;
{
let r1 = &mut x; // r1 在这个作用域内有效
*r1 += 2;
println!(“x: {}”, x);
} // r1 离开作用域
let r2 = &mut x; // ✅ 现在可以再创建一个 `&mut` *r2 += 1; println!("x: {}", x); } 会输出12和13
Rust 的 Borrow Checker 规则
- 同一时间只能有一个可变引用(&mut 变量名),防止数据竞争。
- **可以有多个不可变引用(&),但不能和可变引用混用。
- 可变引用的作用域结束后,才可以创建新的可变引用。
fn modify_value(x: i32) {
x = 100; // ❌ 报错,x 不是可变的
}
fn main() {
let mut num = 5;
modify_value(num);
}
//为什么我改成
fn modify_value(x: i32) {
let x = 100;
}
//不会报错,虽然最后num输出5
fn modify_value(x: i32) {
x = 100; // ❌ 报错,x 不是可变的
}
- 这里
let x = 100;
创建了一个新的局部变量x
,这个变量 遮蔽(shadow) 了原来的x
,但它只是新的x
,不会修改传入的x
。 - 原来的
x
仍然保持不变,函数执行结束后,所有局部变量都会被丢弃。
‘outer_loop是什么?break可以作为什么用?outer += 1;为什么显示unreachable code?
fn main() {
let mut outer = 0;
'outer_loop: loop { let mut inner = 0; loop { println!("Outer: {}, Inner: {}", outer, inner); inner += 1; if inner == 2 { break 'outer_loop; } } outer += 1; } println!("Exited both loops."); }
在 Rust 中outer_loop这个 单引号(
’)开头的标识符 代表一个 循环标签。Rust 允许给循环加上标签,然后
break 或
continue` 时可以指定标签,直接跳出相应的循环。
为什么需要 'outer_loop
?
如果你有嵌套循环,普通的 break
只能退出最近的循环。如果想要直接跳出 外层循环,就需要用 标签 + break 'label
。
因为直接跳出了外层循环所以显示unreachable code
while语法是什么
for语法,rust里的for主要用来遍历什么,遍历Vec![a, b, c]时要注意什么?
while n > 0 {
println!(“{}…”, n);
n -= 1;
}
主要用来遍历Range和动态数组Vec<T>
注意:`for num in numbers` **会消耗 `numbers` 的所有权**(意味着 `numbers` 之后无法再使用)。
如果不希望 `Vec` 被移动?:用for num in numbers.iter()生成不可变引用,或用let mut numbers = vec![1, 2, 3];和
for num in numbers.iter_mut() {}
改成迭代可变引用</T>
fn main() {
for i in 1..6 { // 1..6
表示 1 到 5(不包括 6)
println!(“Number: {}”, i);
}
}
如果希望迭代完numbers后numbers仍然有效/可访问,怎么做?
比如如果你想打印或者修改。
fn main() {
let numbers = vec![10, 20, 30, 40, 50];
for num in numbers { println!("Number: {}", num); } }
改成迭代可变引用
fn main() {
let mut numbers = vec![1, 2, 3];
for num in numbers.iter_mut() { // ✅ 迭代可变引用 *num *= 10; // 修改元素 } println!("Modified Numbers: {:?}", numbers); }
改成不可变引用
fn main() {
let numbers = vec![10, 20, 30];
for num in numbers.iter() { println!("Number: {}", num); } println!("Numbers are still available: {:?}", numbers); }
fn main() {
let s1 = String::from(“Hello”);
let s2 = s1;
println!("{}", s1); } 出什么问题?
fn main() {
let s1 = String::from(“Hello”);
let s2 = s1; // ❌ s1 失效,(因为movement semantic, ownership被移动),s2 获得所有权
println!("{}", s1); // ❌ 编译错误:s1 已移动 } - `s1 = String::from("Hello")` 创建一个 `String`,**`s1` 拥有它的所有权**。 - `let s2 = s1;` **"移动"** 了 `s1` 的所有权给 `s2`,导致 `s1` **失效**,不能再使用。 - **Rust 禁止访问已移动的变量**,防止内存错误。
Rust的哪些数据类型不会发生 Move,而是 Copy?
Rust 只有固定大小的类型(存储在栈上)会 自动 Copy
比如i32:
fn main() {
let x = 5;
let y = x; // ✅ x 仍然有效
println!("x: {}, y: {}", x, y); } i32,u32, f64,bool char,&T,&mut T,Tuple(但如果Tuple有String或Vec<T>)则不会copy
fn takes_ownership(s: String) {
println!(“{}”, s);
} // ❌ s 超出作用域,被释放
fn main() {
let s1 = String::from(“hello”);
takes_ownership(s1); // ❌ s1 被移动到函数中
println!("{}", s1); // ❌ 编译错误,s1 已失效 } 如果s1不是存在heap上的类型也会这样吗
不会!Rust 采用 Move 语义 主要是为了管理堆(Heap)上的数据。如果 s1 是 存储在栈(Stack)上的类型,Rust 不会 Move,而是 Copy,所以 s1 仍然可用。
下面函数有什么问题?
如何解决下面的问题?
fn takes_ownership(s: String) {
println!(“{}”, s);
}
fn main() {
let s1 = String::from(“hello”);
takes_ownership(s1);
println!(“{}”, s1);
}
fn takes_ownership(s: String) {
println!(“{}”, s);
} // ❌ s 超出作用域,被释放
fn main() {
let s1 = String::from(“hello”);
takes_ownership(s1); // ❌ s1 被移动到函数中
println!("{}", s1); // ❌ 编译错误,s1 已失效 }
method 1:传递不可变引用(&s1 传递 不可变引用,不移动所有权**,所以 s1
仍然可用。)
fn borrow_string(s: &String) { // ✅ 只借用,不消耗所有权
println!(“{}”, s);
}
fn main() {
let s1 = String::from(“hello”);
borrow_string(&s1); // ✅ 传递引用
println!("{}", s1); // ✅ s1 仍然有效 }
method 2:返回所有权
fn takes_and_returns(s: String) -> String {
s // ✅ 返回所有权
}
fn main() {
let s1 = String::from(“hello”);
let s2 = takes_and_returns(s1); // ✅ s1 移动到 s2
println!("{}", s2); // ✅ s2 仍然有效 }
如何避免 Move?
-用 .clone() 深拷贝(但可能影响性能)。
- 用 引用 &T 或 &mut T,借用数据,而不消耗所有权。
- 函数返回值 转移所有权,让调用者重新获取控制权。
创建一个i32有3个数字的数组,取名叫arr
let arr: [i32; 3] = [1, 2, 3];
Box<T>是干嘛的</T>
use std::ops::Deref;
// 定义一个递归链表
enum List {
Node(i32, Box<List>), // 使用 Box<T> 存储指针
Nil,
}
以以上为开头构想个递归链表</T></List>
Box<T>允许你将数据存储在堆上,并提供一个指向它的指针</T>
Rust 中,默认变量存储在 栈(stack)上,**但有些情况下需要手动分配在堆上(heap):
- 数据大小在编译时未知(如动态分配对象)。
- 需要存储递归数据结构(如链表、树)。
- 希望转移所有权,但避免数据拷贝。
// 实现一个方法来遍历链表
impl List {
fn print(&self) {
match self {
List::Node(val, next) => {
print!(“{} -> “, val);
next.print();
}
List::Nil => println!(“Nil”),
}
}
}
fn main() {
// 创建链表 1 -> 2 -> 3 -> Nil
let list = List::Node(1, Box::new(
List::Node(2, Box::new(
List::Node(3, Box::new(List::Nil))
))
));
// 打印链表 list.print(); // ✅ 输出: 1 -> 2 -> 3 -> Nil }