//返回一个新的字符串,而不是操作原来的字符串!!! //replace 参数是:被替换内容,用来替换的内容 fnmain() { let string_replace = String::from("I like rust. Learning rust is my favorite!"); let new_string_replace = string_replace.replace("rust", "RUST"); }
//replacen 和前面差不多,不过是替换n个匹配到的 fnmain() { let string_replace = "I like rust. Learning rust is my favorite!"; let new_string_replacen = string_replace.replacen("rust", "RUST", 1); dbg!(new_string_replacen); }
let v = Some(3u8); match v { Some(3) => println!("three"), _ => (), }
//if let匹配 ifletSome(3) = v { println!("three"); }
matches!()宏
将表达式和模式进行匹配,返回True或者False
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
enumMyEnum { Foo, Bar }
fnmain() { let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::Foo]; } //对v进行过滤,只保留类型为MyEnum::Foo的元素 v.iter().filter(|x| matches!(x, MyEnum::Foo));
//更多例子 let foo = 'f'; assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));
let bar = Some(4); assert!(matches!(bar, Some(x) if x > 2));
match和if let匹配导致的变量遮蔽
尽量不要使用同名变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
fnmain() { let age = Some(30); println!("在匹配前,age是{:?}",age); ifletSome(age) = age { println!("匹配出来的age是{}",age); }
println!("在匹配后,age是{:?}",age); }
fnmain() { let age = Some(30); println!("在匹配前,age是{:?}",age); match age { Some(age) => println!("匹配出来的age是{}",age), _ => () } println!("在匹配后,age是{:?}",age); }
match x { Some(50) => println!("Got 50"), Some(n) if n == y => println!("Matched, n = {}", n), //通过匹配守卫,使得在匹配中也可以正常的使用外部变量,而不用担心变量遮蔽的问题 _ => println!("Default case, x = {:?}", x), }
println!("at the end: x = {:?}, y = {}", x, y); }
—————————————————— //匹配守卫的优先级:会作用于所有的匹配项 let x = 4; let y = false;
match x { 4 | 5 | 6if y => println!("yes"), _ => println!("no"), }
match msg { Message::Hello { id: id_variable @ 3..=7 } => { println!("Found an id in range: {}", id_variable) },//@变量绑定,限定范围且绑定变量 Message::Hello { id: 10..=12 } => { println!("Found an id in another range") },//限定了范围,但是这样子只会匹配,而id这个量用不了 Message::Hello { id } => { println!("Found some other id: {}", id) },//可以匹配并绑定到id上,但是这样子限制不了范围 }
fnmain() { // 绑定新变量 `p`,同时对 `Point` 进行解构 let p @ Point {x: px, y: py } = Point {x: 10, y: 23}; println!("x: {}, y: {}", px, py); println!("{:?}", p);
let point = Point {x: 10, y: 5}; iflet p @ Point {x: 10, y} = point { println!("x is 10 and y is {} in {:?}", y, p); } else { println!("x was not 10 :("); } }
fnvec_map(v: &Vec<i32>) -> Vec<i32> { v.iter().map(|element| { // TODO: Do the same thing as above - but instead of mutating the // Vec, you can just return the new number! *element * 2 }).collect() } //map方法由原来的迭代器生成一个新的迭代器,对旧迭代器的每一个方法都调用该闭包
#[test] fnreplace_a_string() { assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool"); assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons"); } }
// A structure to store the goal details of a team. structTeam { goals_scored: u8, goals_conceded: u8, }
fnbuild_scores_table(results: String) -> HashMap<String, Team> { // The name of the team is the key and its associated struct is the value. letmut scores: HashMap<String, Team> = HashMap::new();
for r in results.lines() { let v: Vec<&str> = r.split(',').collect(); let team_1_name = v[0].to_string(); let team_1_score: u8 = v[2].parse().unwrap(); let team_2_name = v[1].to_string(); let team_2_score: u8 = v[3].parse().unwrap(); //注意Team是没有实现可加性的,只可以按照Team内部的元素来操作 let team1 = scores.entry(team_1_name).or_insert(Team{ goals_scored:0, goals_conceded:0 }); team1.goals_scored += team_1_score; team1.goals_conceded += team_2_score; let team2 = scores.entry(team_2_name).or_insert(Team{ goals_scored:0, goals_conceded:0 }); team2.goals_scored += team_2_score; team2.goals_conceded += team_1_score; } scores }
// TODO: Complete the function signature! pubfntransformer(input: Vec<(String,Command)>) -> Vec<String> { // TODO: Complete the output declaration! letmut output: Vec<String> = vec![]; for (string, command) in input.iter() { // TODO: Complete the function body. You can do it! let applied_string:String = match command{ Command::Uppercase => string.to_uppercase(), Command::Trim => string.trim().to_string(), Command::Append(n) => format!("{}{}",string,"bar".repeat(*n)), }; output.push(applied_string); } output } }
#[cfg(test)] mod tests { // TODO: What do we need to import to have `transformer` in scope? use crate::my_module::transformer; use super::Command;
#[test] fnit_works() { let output = transformer(vec![ ("hello".into(), Command::Uppercase), (" all roads lead to rome! ".into(), Command::Trim), ("foo".into(), Command::Append(1)), ("bar".into(), Command::Append(5)), ]); assert_eq!(output[0], "HELLO"); assert_eq!(output[1], "all roads lead to rome!"); assert_eq!(output[2], "foobar"); assert_eq!(output[3], "barbarbarbarbarbar"); } }
从Option中取出值
1 2 3 4 5 6 7 8 9 10 11 12
//如果你确定Option中是有值的,可以使用unwrap()方法直接取出来 let my_option: Option<i32> = Some(5); // 一个Option<i32>类型的变量
let value = my_option.unwrap(); println!("The value is: {}", value);
//如果要处理可能有None的情况,可以使用unwrap_or(初始值) //为None的情况设置一个初始值 let my_option: Option<i32> = Some(5); // 一个Option<i32>类型的变量
let value = my_option.unwrap_or(0); // 如果my_option是None,则使用默认值0 println!("The value is: {}", value);
Option的类型问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14
let range = 10; letmut optional_integers: Vec<Option<i8>> = vec![None];
for i in1..(range + 1) { optional_integers.push(Some(i)); }
fnparse_pos_nonzero(s: &str) -> Result<PositiveNonzeroInteger, ParsePosNonzeroError> { // TODO: change this to return an appropriate error instead of panicking // when `parse()` returns an error. let x: i64 = s.parse().map_err(ParsePosNonzeroError::from_parseint)?; PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation) }
impl Licensed for SomeSoftware {} impl Licensed for OtherSoftware {}
// YOU MAY ONLY CHANGE THE NEXT LINE fncompare_license_types(software:impl Licensed, software_two:impl Licensed) -> bool { software.licensing_info() == software_two.licensing_info() } //下面有SomeSoftware和OtherSoftware两种类型 //用impl Licensed可以指代他们
#[cfg(test)] mod tests { use super::*;
#[test] fncompare_license_information() { let some_software = SomeSoftware {}; let other_software = OtherSoftware {};
impl Rectangle { // Only change the test functions themselves pubfnnew(width: i32, height: i32) -> Self { if width <= 0 || height <= 0 { panic!("Rectangle width and height cannot be negative!") } Rectangle {width, height} } }
#[cfg(test)] mod tests { use super::*;
#[test] fncorrect_width_and_height() { // This test should check if the rectangle is the size that we pass into its constructor let rect = Rectangle::new(10, 20); assert_eq!(rect.width, 10); // check width assert_eq!(rect.height, 20); // check height }
#[test] #[should_panic] fnnegative_width() { // This test should check if program panics when we try to create rectangle with negative width let _rect = Rectangle::new(-10, 10);
}
#[test] #[should_panic] fnnegative_height() { // This test should check if program panics when we try to create rectangle with negative height let _rect = Rectangle::new(10, -10); } }
// Step 2. // Apply the `capitalize_first` function to a slice of string slices. // Return a vector of strings. // ["hello", "world"] -> ["Hello", "World"] pubfncapitalize_words_vector(words: &[&str]) -> Vec<String> { words.iter().map( |&word| { capitalize_first(word) } ).collect() }
// Step 3. // Apply the `capitalize_first` function again to a slice of string slices. // Return a single string. // ["hello", " ", "world"] -> "Hello World" pubfncapitalize_words_string(words: &[&str]) -> String { words.iter().map( |&word| { capitalize_first(word) } ).collect() }
首先,我要衷心感谢所有给予我帮助助教导师。每次我有困惑的时候他们的专业知识和耐心指导帮我解决一系列棘手的问题。通过这个平台可以很好的交到对这方面感兴趣的朋友,在群里跟朋友们讨论让我可以更好地理解和应用 Rust 语法。此外,也离不开Rust 社区分享的宝贵的学习资料。同时课堂上分享的The Rust Reference 不失为一本经典巨作给我前期的语法学习提供很有力的帮助。 在开始开发操作系统之前,先熟悉 Rust 语言的基础知识,包括语法、类型系统、所有权和生命周期等概念为首要目标。选择Rust是因为他的安全性和性能使其成为编写操作系统的理想选择。在正式做练习之前花了很多时间在环境配置上面,之前学过的harmony os 都是他们给的镜像直接导入,第一次在上面搭建问了很多导师问题,他们都耐心的回答我,让我在这方面更有兴趣。比如在当推送本地更改时,如果远程仓库已经有了更新,可能会出现合并冲突,需要手动解决这些冲突。通过这些学习能更好的完成后面几个阶段的学习。 和其他语言对比在生命周期这个方面Rust 强制使用生命周期来检查引用的有效性,以避免悬空引用和数据竞争。生命周期注解使得 Rust 的借用系统变得更加严格和安全。C++ 中也有生命周期的概念,但它通常通过使用智能指针、RAII(资源获取即初始化)等技术。相比rust在这方面更不容易出错。而且在所有权上面Rust 引入了所有权和借用的概念,这是与 C++ 最明显的区别之一。在 Rust 中,每个值都有一个所有者,并且在任何时候只能有一个可变借用或任意数量的不可变借用。这确保了在编译时不会出现数据竞争。在以前学过的 C++ 中,没有类似的所有权和借用系统,开发人员需要手动管理内存和资源,这可能导致内存泄漏、悬空指针和其他常见的错误
1 2 3 4 5 6 7 8 9 10 11 12
fn main() { let result; { let x = 5; result = compute(&x); } println!("Result: {}", result); }
fn compute<'a>(value: &'a i32) -> &'a i32 { value }
有一个 main 函数,它调用了一个 compute 函数来计算一个整数的引用,并将结果赋值给 result 变量。然后我们尝试在 main 函数中打印 result 的值。然而,compute 函数返回了一个指向局部变量 x 的引用,而 x 的生命周期只在包含它的代码块内有效。由于 x 在 compute 函数返回后就会被销毁,所以返回的引用将指向无效的内存,导致悬垂引用错误。后期我发现需要通过修改函数签名来指定一个更长的生命周期,或者避免返回对局部变量的引用
1 2 3 4 5 6 7 8 9 10 11 12
fn main() { let result; { let x = 5; result = compute(x); } println!("Result: {}", result); }
这个任务主要是为了获取任务信息,通过引入新的系统调用 sys_task_info,操作系统增强了对任务的监控和管理能力。现在,系统管理员可以根据任务 ID 查询到任务的详细信息,包括当前任务的状态、已经执行的系统调用及其调用次数,以及任务的总运行时长。这个功能使得系统能够更加细致地了解任务的运行情况,有助于优化系统资源的分配,提高系统的整体性能和稳定性。同时,对于开发人员来说,这也提供了一个更好的调试工具,可以更方便地跟踪和分析任务的行为,帮助定位和解决潜在的问题。
root@os1:/mnt/gdb-14.2/build-riscv64# ./bin/riscv64-unknown-elf-gdb --version GNU gdb (GDB) 14.2 Copyright (C) 2023 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. root@os1:/mnt/gdb-14.2/build-riscv64# ll ./bin/ total 238428 drwxr-xr-x 1 root root 4096 May 13 03:10 ./ drwxr-xr-x 1 root root 4096 May 13 03:10 ../ -rwxr-xr-x 1 root root 232530576 May 13 03:10 riscv64-unknown-elf-gdb* -rwxr-xr-x 1 root root 4627 May 13 03:10 riscv64-unknown-elf-gdb-add-index* -rwxr-xr-x 1 root root 11605272 May 13 03:10 riscv64-unknown-elf-run*
root@os1:/mnt/2024s-rcore-xuejianxinokok/os/target/riscv64gc-unknown-none-elf/debug# file os os: ELF 64-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked,
with debug_info, not stripped <<<<<<< 注意是这行
# 或者直接读取section 信息,发现有debug_info 这些section root@os1:/mnt/2024s-rcore-xuejianxinokok/os/target/riscv64gc-unknown-none-elf/debug# readelf -SW os There are 18 section headers, starting at offset 0x2952a8:
Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 0000000080200000 001000 00a340 00 AX 0 0 4 [ 2] .rodata PROGBITS 000000008020b000 00c000 0334ab 00 AM 0 0 4096 [ 3] .data PROGBITS 000000008023f000 040000 028920 00 WA 0 0 8 [ 4] .bss NOBITS 0000000080268000 068920 038660 00 WA 0 0 8 [ 5] .debug_abbrev PROGBITS 0000000000000000 068920 006a82 00 0 0 1 [ 6] .debug_info PROGBITS 0000000000000000 06f3a2 073718 00 0 0 1 [ 7] .debug_aranges PROGBITS 0000000000000000 0e2aba 0061b0 00 0 0 1 [ 8] .debug_str PROGBITS 0000000000000000 0e8c6a 08d4ab 01 MS 0 0 1 [ 9] .comment PROGBITS 0000000000000000 176115 000048 01 MS 0 0 1 [10] .riscv.attributes RISCV_ATTRIBUTES 0000000000000000 17615d 00003e 00 0 0 1 [11] .debug_frame PROGBITS 0000000000000000 1761a0 007f08 00 0 0 8 [12] .debug_line PROGBITS 0000000000000000 17e0a8 040627 00 0 0 1 [13] .debug_ranges PROGBITS 0000000000000000 1be6cf 033b00 00 0 0 1 [14] .debug_loc PROGBITS 0000000000000000 1f21cf 000b72 00 0 0 1 [15] .symtab SYMTAB 0000000000000000 1f2d48 096048 18 17 25465 8 [16] .shstrtab STRTAB 0000000000000000 288d90 0000b5 00 0 0 1 [17] .strtab STRTAB 0000000000000000 288e45 00c462 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), p (processor specific)
这时我们就可以在 容器内的命令行进行调试了,但这样还是不太方便
进入gbd 后
先回车后 ,然后再输入 b rust_main
1 2
b rust_main Breakpoint 1 at 0x8020618a: file src/main.rs, line 98.