lab02
概述
COM6991lab02
这里是COM6991有关rust的基础语法的实验,个人写完后的总结。
这个实验主要是了解rust的基本类型,常见的错误处理哲学(使用result, ?等方法处理).
实验部分
任务一 tribonacci
实现计算一个变量的tribonacci数组和他们的和,
实现的思路就是利用rust的数组特性,并且根据公式v[i] = v[i - 1] + v[i - 2] + v[i - 3]
进行实现,
因此我们可以编写如下代码
use std::env;
use std::num::ParseIntError;
// use std::result::Result;
struct TribonacciError(String);
fn main() {
let args: Vec<String> = env::args().collect();
let error_message = String::from("Please enter a valid size");
let size = match args.get(1) {
Some(s) => s.parse::<usize>(),
None => Ok(10),
};
if let Err(e) = compute_tribonacci(size, error_message) {
println!("Error: {}", e.0)
}
}
/// Computes the tribonacci sequence of a given size
/// Prints the sequence, and its sum
fn compute_tribonacci(size: Result<usize, ParseIntError>, error_msg: String) -> Result<(), TribonacciError> {
let mut v:Vec<u128> = vec![1_u128; 3]; // 初始化数组
let s = size.map_err(|_|TribonacciError(error_msg))?;
for i in 3..s {
v.push(v[i - 1] + v[i - 2] + v[i - 3]);
}
println!("Values: {:?}", v);
let sum:u128 = v.iter().sum();
println!("\nsum:{sum}");
Ok(())
}
这里的map_err()的作用就是将
Result<T, E>
类型转换为Result<T, F>
类型, ?的这个意思表示如果是Err(F)则返回,可以节约书写match的成本,我们可以使用.sum()函数对于迭代器作求和操作。
任务二 Toupper
这个任务是要将所有在字符串中的字符变成大写,这个的实现思路比较简单,只需要调用to_uppercase函数即可
fn main() {
// try and get the first argument
// using some iterator methods
let arg = std::env::args().nth(1).expect("must be passed in");// get the first argument
// the compiler suggests to "borrow here"
// but we haven't learnt how to borrow :(
// we have a String type, and want to get a &str
// Try find a function that can help us using
// the docs https://doc.rust-lang.org/stable/std/string/struct.String.html
let upp = uppercase(&arg);
println!("arg = {}", arg);
println!("upp = {}", upp);
}
fn uppercase(src: &str) -> String {
let mut destination = String::new();
for c in src.chars() {
// this doesn't work either!!
// what type does to_uppercase return?
// what type does push expect?
// Food for thought, what exactly is src.chars()?
for c in c.to_uppercase() {
destination.push(c);
}
// destination.push(c.to_uppercase().next().expect("must be a char"));
}
destination
}
这里需要注意的是src.chars()和c.to_uppercase都是迭代器返回值,这里的第二个循环可以写成
destination.push(c.to_uppercase().next().expect(“must be a char”));这种形式
任务三 Collections
rust中常见的容器的API调用
use core::time;
use std::collections::{linked_list, HashMap, LinkedList, VecDeque};
const MAX_ITER: i32 = 300000;
fn main() {
// Vectors
vec_operations();
// VecDeque
vec_deque_operations();
// TODO: your code here, for linked list insertions
linked_list_operations();
// TODO: your code here, for hashmap insertions
hashmap_operations();
// TODO: your text explanation to the questions in the spec
}
/// measure the insertion and removal
/// operations of a vector
fn vec_operations() {
let mut vec = Vec::new();
let time_start = std::time::Instant::now();
for i in 0..MAX_ITER {
vec.push(i);
}
let time_end = std::time::Instant::now();
println!("==== Vector ====");
println!("insert: {:?}", time_end - time_start);
let time_start = std::time::Instant::now();
for _ in 0..MAX_ITER {
vec.remove(0);
}
let time_end = std::time::Instant::now();
println!("remove: {:?}", time_end - time_start);
}
/// measure the insertion and removal
/// operations of a VecDeque
fn vec_deque_operations() {
let mut vec_deque = VecDeque::new();
let time_start = std::time::Instant::now();
for i in 0..MAX_ITER {
vec_deque.push_back(i);
}
let time_end = std::time::Instant::now();
println!("==== VecDeque ====");
println!("insert: {:?}", time_end - time_start);
let time_start = std::time::Instant::now();
for _ in 0..MAX_ITER {
vec_deque.pop_front();
}
let time_end = std::time::Instant::now();
println!("remove: {:?}", time_end - time_start);
}
fn linked_list_operations() {
let mut linked_list: LinkedList<i32> = LinkedList::new();
let time_start = std::time::Instant::now();
for i in 0..MAX_ITER {
linked_list.push_back(i);
}
let time_end = std::time::Instant::now();
println!("===LinkedList===");
println!("Insert:{:?}", time_end - time_start);
let time_start = std::time::Instant::now();
for _ in 0..MAX_ITER {
linked_list.pop_front();
}
let time_end = std::time::Instant::now();
println!("Remove:{:?}", time_end - time_start);
}
fn hashmap_operations() {
let mut hashmap:HashMap<i32, i32> = HashMap::new();
let time_start = std::time::Instant::now();
for i in 0..MAX_ITER {
hashmap.insert(i, i);
}
let time_end = std::time::Instant::now();
println!("Insert: {:?}", time_end - time_start);
}
任务四 data analysis
分析出一个学校到底有多少学生,最受欢迎的课程是什么,最不受欢迎的课程是什么。
const ENROLMENTS_PATH: &str = "enrolments.psv";
use csv::{Position, ReaderBuilder};
use serde::Deserialize;
use std::{collections::HashMap, fs::File, hash::Hash};
// 定义一个结构体来映射 PSV 文件中的列
#[derive(Debug, Deserialize)]
struct Record {
// 根据你的 PSV 文件结构定义字段
course_code:String,
student_number:String,
name:String,
program:String,
plan:String,
wam:f64,
session:String,
birthday:String,
sex:String
}
fn main() {
let file = File::open(ENROLMENTS_PATH).expect("open the file");
let mut reader = ReaderBuilder::new().delimiter(b'|').has_headers(false).from_reader(file);
let mut students:HashMap<String, Record> = HashMap::new();
for result in reader.deserialize::<Record>() {
let record = result.expect("一条记录");
// println!("{:?}\n", record);
students.insert(record.student_number.clone(), record);
}
println!("the students:{:?}", students.len());
let mut courses:HashMap<String, i32> = HashMap::new();
reader.seek(Position::new()).unwrap();
for result in reader.deserialize::<Record>() {
let record = result.expect("一条记录");
courses.entry(record.course_code)
.and_modify(|x|(*x += 1))
.or_insert(1);
}
let (course, number) = courses.iter().max_by_key(|(course_id, number)|*number).expect("the courses not null");
let (course2, number2) = courses.iter().min_by_key(|(key, value)|*value).expect("this courses not null");
println!("the least common course {}, the number is {}", course2, number2);
println!("the most common course {}, the number is {}", course, number);
let total_wam = students.values().map(|student| student.wam).sum::<f64>();
let average_wam = total_wam / students.len() as f64;
println!("the average wam is {:.02}\n", average_wam);
// println!("Hello, world!");
}
这个任务主要是让我们熟悉如何使用函数命令实现rust中一些功能而不是使用for loop 循环
其中对于hashmap而言,map.len()返回key的数量,map.values()返回map容器中值的迭代器
map.entry(key).and_modify(|value|*value+1).or_insert(1);这种做法类似于c++中的hashmap
map.iter().max_by_key(|(key, val)|*val).expect(“the map not null”)返回按照值排列的最大(key, val)
map.iter().map(|(key, value)|key+value).sum() 返回所有Key和value的和。