Rust语法 Flashcards

1
Q

打印的函数

A

print!()和println!()
注意放在main中
println!(“Color: ({}, {}, {})”, color.r, color.g, color.b);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

rust unit type

A

类型是()
唯一的值:()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

显示返回和隐式返回

A

return x+y;
x + y

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

函数式样

A

fn functionname(parameter1:type, parameter2:type) -> return_type{

}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

声明可变变量/声明不可变变量

rust想改变真正改变值的引用需要用?

let &mut x = 3;有问题吗,为什么?有问题的话怎么改。

A

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)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

rust的内置函数类型:
有符号整数
无符号整数
浮点数类型
字符类型
字符串类型
C风格数组的创建

A

整数类型

有符号整数(i8 ~ i128):i8, i16, i32, i64, i128
- 无符号整数(u8 ~ u128u8, 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]]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

rust类型可以随意更改嘛,可以不规定rust的数据类型嘛,比如let a = 42;

A

不可以,它是强类型。可以不规定,它会自动推导。

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

fn swap(x:i32, y:i32) {
let t = y;
y = x;
x = t
}
这是按值传递pass by value,按值传递说明什么?有两个方法可以改,怎么改?

A

按值传递=传递副本
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);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

fn modify_value(x: i32) {
x = 100;
}

fn main() {
let mut num = 5;
modify_value(num);
}
结果是什么?
为什么会发生这样的现象

A

注意函数里的参数没有声明可变,要声明改成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 只是传值,函数内的修改不会影响原变量
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

fn modify_value(mut x: i32) {
x = 100;
}

fn main() {
let mut num = 5;
modify_value(num);
print!(“{}”, num)
}
// 这个会输出什么?为什么

A
  1. main 函数中,num 被定义为 let mut num = 5;,意味着它是一个可变变量。
  2. 然后 modify_value(num); 被调用,把 num 的值传递给 modify_value 函数。
  3. 但是,modify_value(mut x: i32) 只是对 x 进行了修改,而 ==x 只是 num拷贝(Rust 的 i32 类型默认是按值传递,而不是引用)。==
  4. modify_value 内部的 x = 100; 只是修改了 x 的拷贝,而 num 并没有被改变。
  5. 所以,print!("{}", num); 依然输出 5。(虽然不会报错)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

fn modify_value(x: i32) {
x = 100;
}

fn main() {
let mut num = 5;
modify_value(num);
}
怎么改能够让num=100

A

fn modify_value(x: &mut i32) {
*x = 100;
}

fn main() {
let mut num = 5;
modify_value(&mut num);
print!(“{}”, num)
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

fn main() {
let mut x = 10;

let r1 = &mut x; 
let r2 = &mut x; 
println!("{}", r1);  } 有什么问题,如果非要有r1和r2该怎么改
A

在同一作用域内,不能同时存在多个可变引用(&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
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Rust 的 Borrow Checker 规则

A
  1. 同一时间只能有一个可变引用(&mut 变量名),防止数据竞争。
  2. **可以有多个不可变引用(&),但不能和可变引用混用。
  3. 可变引用的作用域结束后,才可以创建新的可变引用。
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

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

A

fn modify_value(x: i32) {
x = 100; // ❌ 报错,x 不是可变的
}

  • 这里 let x = 100; 创建了一个新的局部变量 x,这个变量 遮蔽(shadow) 了原来的 x,但它只是新的 x不会修改传入的 x
  • 原来的 x 仍然保持不变,函数执行结束后,所有局部变量都会被丢弃
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

‘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."); }
A

在 Rust 中outer_loop这个 单引号()开头的标识符 代表一个 循环标签。Rust 允许给循环加上标签,然后 breakcontinue` 时可以指定标签,直接跳出相应的循环。

为什么需要 'outer_loop

如果你有嵌套循环,普通的 break 只能退出最近的循环。如果想要直接跳出 外层循环,就需要用 标签 + break 'label
因为直接跳出了外层循环所以显示unreachable code

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

while语法是什么

for语法,rust里的for主要用来遍历什么,遍历Vec![a, b, c]时要注意什么?

A

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);
}
}

17
Q

如果希望迭代完numbers后numbers仍然有效/可访问,怎么做?
比如如果你想打印或者修改。
fn main() {
let numbers = vec![10, 20, 30, 40, 50];

for num in numbers {
    println!("Number: {}", num);
} }
A

改成迭代可变引用

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); }
18
Q

fn main() {
let s1 = String::from(“Hello”);
let s2 = s1;

println!("{}", s1);  } 出什么问题?
A

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 禁止访问已移动的变量**,防止内存错误。
19
Q

Rust的哪些数据类型不会发生 Move,而是 Copy?

A

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
20
Q

fn takes_ownership(s: String) {
println!(“{}”, s);
} // ❌ s 超出作用域,被释放

fn main() {
let s1 = String::from(“hello”);
takes_ownership(s1); // ❌ s1 被移动到函数中

println!("{}", s1); // ❌ 编译错误,s1 已失效 } 如果s1不是存在heap上的类型也会这样吗
A

不会!Rust 采用 Move 语义 主要是为了管理堆(Heap)上的数据。如果 s1 是 存储在栈(Stack)上的类型,Rust 不会 Move,而是 Copy,所以 s1 仍然可用。

21
Q

下面函数有什么问题?
如何解决下面的问题?
fn takes_ownership(s: String) {
println!(“{}”, s);
}

fn main() {
let s1 = String::from(“hello”);
takes_ownership(s1);
println!(“{}”, s1);
}

A

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 仍然有效 }
22
Q

如何避免 Move?

A

-用 .clone() 深拷贝(但可能影响性能)。
- 用 引用 &T 或 &mut T,借用数据,而不消耗所有权。
- 函数返回值 转移所有权,让调用者重新获取控制权。

23
Q

创建一个i32有3个数字的数组,取名叫arr

A

let arr: [i32; 3] = [1, 2, 3];

24
Q

Box<T>是干嘛的</T>

use std::ops::Deref;

// 定义一个递归链表
enum List {
Node(i32, Box<List>), // 使用 Box<T> 存储指针
Nil,
}
以以上为开头构想个递归链表</T></List>

A

Box<T>允许你将数据存储在堆上,并提供一个指向它的指针</T>

Rust 中,默认变量存储在 栈(stack)上,**但有些情况下需要手动分配在堆上(heap):

  1. 数据大小在编译时未知(如动态分配对象)。
  2. 需要存储递归数据结构(如链表、树)。
  3. 希望转移所有权,但避免数据拷贝。

// 实现一个方法来遍历链表
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 }
25
所有权转移的本质是释放内存吗?
所有权转移的本质是是把变量的所有权交给另一个变量,原变量不能再使用。
26
Rust 的所有权(ownership)、移动(move)、借用(borrow) 规则 为什么下面两个函数一个的r1可以,一个的s1不行。 fn main() { let x = 5; let r1 = &x; // ✅ 不可变引用 let r2 = &x; // ✅ 另一个不可变引用 println!("{} {}", r1, r2); // ✅ 允许多个不可变引用 } fn main() { let s1 = String::from("Hello"); let s2 = s1; // ❌ s1 失效,s2 获得所有权 println!("{}", s1); // ❌ 编译错误:s1 已移动 }
在 Rust 中,移动语义(Move Semantics)指的是: -变量赋值或传递时,默认移动数据的所有权,而不是复制。 - 被移动的变量将失效,无法再使用,从而避免 二次释放(Double Free) 和 悬垂指针(Dangling Pointer)问题。 比如 fn main() { let s1 = String::from("Hello"); let s2 = s1; // ❌ s1 失效,s2 获得所有权 println!("{}", s1); // ❌ 编译错误:s1 已移动 } String 由三部分组成: 指针(指向堆上数据) 长度 容量 这些数据存储在 栈 上,但 指针指向的内容存储在堆上。 当 let s2 = s1; 发生时,Rust 只复制了栈上的指针、长度、容量,而没有克隆堆上的数据。 这意味着 s1 和 s2 指向同一块内存,如果 s1 仍然有效,Rust 可能会导致 双重释放(double free)错误,所以 s1 直接失效。 对于 x = 5 是 i32 类型,它是一个存储在栈上的数据类型。 所有存储在栈上的基本类型(Copy trait)都默认使用“复制”而不是“移动”。 let r1 = &x; let r2 = &x; 只是创建了不可变引用(borrow),并没有移动 x 的所有权,所以 x 仍然有效。
27
fn main(){ let s1 = String::from("Hello"); let s2 = s1; println!("s1: {}, s2: {}", s1, s2); } 如何让s1可用?
method 1: 如果想要 s1 和 s2都拥有独立的数据,可以使用 .clone() fn main(){ let s1 = String::from("Hello"); let s2 = s1.clone(); println!("s1: {}, s2: {}", s1, s2); } method 2: 用borrow,不消耗ownership,缺点是只能读取不能修改 fn main(){ let s1 = String::from("Hello"); let s2: &String = &s1; println!("s1: {}, s2: {}", s1, s2); } method 3:使用可变引用 缺点:一个变量只能同时有一个可变引用(&mut T)。 当 s2 仍然有效时,不能使用 s1。 fn main() { let mut s1 = String::from("Hello"); let s2: &mut String = &mut s1; // ✅ 可变借用 s1 s2.push_str(", Rust!"); // ✅ 修改 s1 的内容 println!("{}", s2); // ✅ 只能使用 s2,因为 s1 目前被可变借用 }
28
存在tuple里的元素如果是可变的: let tup1 = (5, String::from("hello")); 可变数组如果作为参数被调用: fn main() { let s1 = String::from("hello"); takes_ownership(s1); println!("{}", s1); } 会发生什么? 作为参数调用的想个解决方案?
会发生ownership move,即变量赋值或传递时,默认移动数据的所有权,而不是复制。被移动的变量将失效,无法再使用。 // 传递时可以传递不可变引用,此时只借用,不消耗所有权 fn borrow_string(s: &String) { // ✅ 只借用,不消耗所有权 println!("{}", s); } fn main() { let s1 = String::from("hello"); borrow_string(&s1); // ✅ 传递引用 println!("{}", s1); // ✅ s1 仍然有效 }
29
请使用 Rust 枚举(enum)定义一个类型 Dimension,它可以表示 0 维、2 维和 3 维的坐标。 如何访问?
enum [TypeName] { {[Variant name]{([Stored value type],…)}, [Variant name]{([Stored value type],…)}, …} } enum Dimension { Zero, // 没有任何数据 Two(i32, i32), // 代表二维坐标 (x, y) Three(i32, i32, i32) // 代表三维坐标 (x, y, z) } 在 Rust 里,这种enum带不同数量字段的变体 叫做 代数数据类型(Algebraic Data Type,ADT),具体来说,它是 枚举(Enum)中的变体(Variant),其中包含数据的变体被称为 “带数据的枚举变体”(Data-carrying Variants)。 let point = Dimension::Two(9, 6);
30
for num in numbers.iter()等效的迭代方式?
for num in &numbers { // 等价于 numbers.iter() println!("{}", num); }
31
enum Dimension { Zero, // 没有任何数据 Two(i32, i32), // 代表二维坐标 (x, y) Three(i32, i32, i32) // 代表三维坐标 (x, y, z) } 写个订阅枚举的函数
fn describe(dim: Dimension){ match dim { Dimension::Zero => println!("This is a point with no coordinates."), Dimension::Two(x, y) => println!("2D Point: ({}, {})", x, y), Dimension::Three(x, y, z) => println!("3D Point: ({}, {}, {})", x, y, z), } }
32
在rust里字符串的类型,有什么区别?
Rust 有两种字符串类型: 1. str(字符串切片):存储在栈(Stack)上,不可变,通常以 &str形式出现。 2. String(字符串对象):存储在 堆(Heap)上,可变,可以动态扩展。 用String::from和"hello".to_string()都可以 let s1 = String::from("hello"); // ✅ 用 `String::from()` let s2 = "hello".to_string(); // ✅ 用 `.to_string()`
33
指出下列数据类型哪个是用copy哪个是用move哪个是借用? i32, f64, String, Vec, Box,char, bool, usize, &str, [T; N],&T, &mut T,tuple(看内容物)
copy:i32, f64, char, bool, usize, &str, [T; N],Tuple(简单类型) borrow:&T, &mut T, move:String, Vec, Box 注意:如果Tuple包含 String 或 Vec则不会copy heap:变量存储在栈上,但指针指向堆 以下为补充内容: 1. Rust 默认 Move,而不是 Copy: - `String`, `Vec` **默认移动所有权**,被移动后原变量无效。 - `i32`, `bool` **默认 Copy**,不会移动所有权。 2. 如何避免 Move? - 用 `.clone()` **深拷贝**(但可能影响性能)。 - 用 引用 &T 或 &mut T,借用数据,而不消耗所有权。 - 函数返回值 **转移所有权**,让调用者重新获取控制权。
34
rust的:和::有啥区别 类型转换用什么关键词 自定义类型转换的关键词
单冒号 `:` 用于变量类型声明:let x: i32 = 10; // 明确声明 x 的类型是 i32 而双冒号 `::` 用于访问关联函数或者常量:let x = i32::from(10); // i32 结构体的 from() 方法 let pi = std::f64::consts::PI; // 访问标准库的 PI 常量 用as:let y = 3 as f64; // 直接转换为 f64 用Into和From
35
默认初始化值的语法,即default trait。
#[derive(Default)] struct Config { width: u32, height: u32, } fn main() { let default_config = Config::default(); println!("{} x {}", default_config.width, default_config.height); // 0 x 0 }