// primitive_types2.rs // // Fill in the rest of the line that has code missing! No hints, there's no // tricks, just get used to typing these :) // // Execute `rustlings hint primitive_types2` or use the `hint` watch subcommand // for a hint.
fnmain() { // Characters (`char`)
// Note the _single_ quotes, these are different from the double quotes // you've been seeing around. let my_first_initial = 'C'; if my_first_initial.is_alphabetic() { println!("Alphabetical!"); } elseif my_first_initial.is_numeric() { println!("Numerical!"); } else { println!("Neither alphabetic nor numeric!"); }
let your_character = '☢️'; // Finish this line like the example! What's your favorite character? // Try a letter, try a number, try a special character, try a character // from a different language than your own, try an emoji! if your_character.is_alphabetic() { println!("Alphabetical!"); } elseif your_character.is_numeric() { println!("Numerical!"); } else { println!("Neither alphabetic nor numeric!"); } }
// structs3.rs // // Structs contain data, but can also have logic. In this exercise we have // defined the Package struct and we want to test some logic attached to it. // Make the code compile and the tests pass! // // Execute `rustlings hint structs3` or use the `hint` watch subcommand for a // hint.
在第一阶段的学习中,我巩固了我们所掌握的rust基础,并开始学习操作系统相关的知识。在这一部分,我还培养了我的思考能力,深入思考了rust的安全与不安全的地方。同时,通过和群友的交流,我也展开了对更多其它知识点的思考,比如“Copy”、“Clone”特征和“Drop”的冲突之处。 最重要的是,我深深意识到:Talk is cheap, show me the code!
第一是出现了“File is shorter than the first ELf header part”,翻译过来就是,文件比文件描述符还短。我通过调试,发现是在测试“ch5_spawn0”的时候,报了这个错误。我分析,这个问题可能的最直接原因只有三个,要么是文件本身就不存在,要么是该文件没被读取进来,要么是该文件被损坏了。我通过查看测试用例,发现该文件是存在的,那就只可能是该文件没被读进来或者该文件已被损坏。分析概率,我严重怀疑是该文件已被损坏了。毕竟,读入文件的代码只比ch5多了2行,我的ch5已经通过了,况且读入文件的底层实现不是我做的,那很可能不是读入文件的时候出现的问题。最有可能就是我写的“在可以释放内存时进行内存释放”的操作有问题,导致损坏了其他的文件,比如这个文件。
但是刚刚那个只是第一个问题!还有一个很坑的问题,我在解决上一个之后,又遇到了“IoError”!报错提示为“VitBlock:IoError”,真是奇怪,怎么还出现IoError了?我再次尝试了大量的解决方法,各种寻找可能的问题,但还是不知道原因。但是,我突然发现,在LOG=TRACE或LOG=DEBUG下,我执行测试,居然没有报错!这是为什么?我意识到了一个可能的关键:时间!在使用LOG时,程序的运行时间会变慢!这可能就给os留足了时间,使其能够完成从存储中的加载,就不会引发错误。而不使用LOG时,可能就因为时间过短,导致os来不及完成加载,从而引发IoError。但这是为什么呢?经过分析,我定位到了出错的核心位置,那里我使用的是if let 语句。后续,我将其改成了let之后再进行match,就解决了问题。
Rust学习过程主要参考阅读了《Rust圣经》、《Rust by Example》、和Rust之旅 之后的时间主要是对《Rust圣经》中的进阶部分和基础部分进行阅读笔记并复习,基础部分难点主要集中在所有权和特征这两个知识点上,对于生命周期以及包和模块的讨论并不是特别深入。进阶部分都难哈哈哈哈,迭代器和智能指针还算比较好理解些,对于迭代器加闭包实现的函数式编程每次都让我觉得很强大,Cell和RefCell提供的内部可变性加上智能指针也给程序提供了很大的灵活性的前提下保证了一定的安全性。生命周期的使用也是一大难点了。之后还有unsafe Rust的使用以及宏编程(对比C/C++的难的多但功能性也更强大)
match y { Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y), _ => panic!("no match!"), } y;
这样写会报错(value used here after partial move),因为在最后返回 y 之前 Some(p)就已经把外面 y 的所有权移动到 p 上了,此时 y 指向的是一个无效的内存空间。所以现在的解决方案就是把外面 y 借用到 Some(p)之中,一个关键字 ref 可以帮助我们做到这一点。这个关键字其实用法还是挺多的,一般用于模式匹配:
error[E0507]: cannot move out of `borrowed_car.engine` as enum variant `Some` which is behind a shared reference --> src/main.rs:16:11 | 16 | match borrowed_car { | ^^^^^^^^^^^^ 17 | Some(&Car { engine }) => { | ------ | | | data moved here | move occurs because `engine` has type `Engine`, which does not implement the `Copy` trait | help: consider borrowing the pattern binding | 17 | Some(&Car { ref engine }) => { | +++
error[E0716]: temporary value dropped while borrowed --> src/main.rs:10:44 | 10 | let borrowed_car: Option<&Car> = Some(&Car { | ____________________________________________^ 11 | | engine: Engine { 12 | | version: String::from("混合动力"), 13 | | }, 14 | | }); | | ^ - temporary value is freed at the end of this statement | |_____| | creates a temporary value which is freed while still in use 15 | 16 | match borrowed_car { | ------------ borrow later used here | help: consider using a `let` binding to create a longer lived value | 10 ~ let binding = Car { 11 + engine: Engine { 12 ~ version: String::from("混合动力"), 13 + }, 14 + }; 15 ~ let borrowed_car: Option<&Car> = Some(&binding); |
上面这些概念之间的关系就是: The temporary scope of an expression is the scope that is used for the temporary variable that holds the result of that expression when used in a place context。(摘自文献 3)
注意这里的三个关键词:temporary scope、temporary variable 和 place context
处于位置上下文(place context)的表达式就是位置表达式,它代表了一个内存位置(Paths)。这些表达式是局部变量、静态变量、解引用(*expr)表达式、数组索引表达式(expr[expr])、字段引用(expr.f)和括号内的位置表达式(parenthesized place expressions)
大概就是说,我们讲到生命周期(lifetime)就是总是从代码层面去分析对不对?去看是不是你变量的第一次声明和最后一次使用跨越了一个 block,但是实际上 Rust 做这个生命周期是为了检查内存的有效性的,你还可以从变量指向内存的位置和保证内存的有效性这两个角度来理解生命周期。(Thinking about lifetime as regions of memory, what can they——the reference point to?)