rust练习-生命周期、错误处理
类型转换
裸指针和代表内存地址的整数互相转换
// 填空
fn main() {
let mut values: [i32; 2] = [1, 2];
let p1: *mut i32 = values.as_mut_ptr();
let first_address: usize = p1 as usize;
let second_address = first_address + 4; // 4 == std::mem::size_of::<i32>()
let p2: *mut i32 = second_address as *mut i32; // p2 指向 values 数组中的第二个元素
unsafe {
// 将第二个元素加 1
//
*p2 += 1;
}
assert_eq!(values[1], 3);
println!("Success!")
}
try_from/try_into
// TryFrom 和 TryInto 也被包含在 `std::prelude` 中, 因此以下引入是没必要的
// use std::convert::TryInto;
fn main() {
let n: i16 = 256;
// Into 特征拥有一个方法`into`,
// 因此 TryInto 有一个方法是 ?
let n: u8 = match n.try_into() {
Ok(n) => n,
Err(e) => {
println!("there is an error when converting: {:?}, but we catch it", e.to_string());
0
}
};
assert_eq!(n, 0);
println!("Success!")
}
String parse
// 为了使用 `from_str` 方法, 你需要引入该特征到当前作用域中
use std::str::FromStr;
fn main() {
let parsed: i32 = "5 ".trim().parse().unwrap();
let turbo_parsed = "10".parse::<i32>().unwrap();
let from_str: i32 = "20".parse().unwrap();
let sum = parsed + turbo_parsed + from_str;
assert_eq!(sum, 35);
println!("Success!")
}
Display trait
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
// 实现fmt时会自动实现to_string()
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "The point is ({}, {})", self.x, self.y)
}
}
fn main() {
let origin = Point { x: 0, y: 0 };
// 填空
assert_eq!(origin.to_string(), "The point is (0, 0)");
assert_eq!(format!("{}", origin), "The point is (0, 0)");
println!("Success!")
}
{}和{:?}
{}
:fmt
{}
: debug
与 {}
类似,{:?}
也是占位符:
{}
适用于实现了std::fmt::Display
特征的类型,用来以更优雅、更友好的方式格式化文本,例如展示给用户{:?}
适用于实现了std::fmt::Debug
特征的类型,用于调试场景
其实两者的选择很简单,当你在写代码需要调试时,使用 {:?}
,剩下的场景,选择 {}
。
rust类型别名,带泛型
use std::num::ParseIntError;
// 填空
type Res<T> = std::result::Result<T, ParseIntError>;
// 使用上面的别名来引用原来的 `Result` 类型
fn multiply(first_number_str: &str, second_number_str: &str) -> Res<i32> {
first_number_str.parse::<i32>().and_then(|first_number| {
second_number_str.parse::<i32>().map(|second_number| first_number * second_number)
})
}
// 同样, 这里也使用了类型别名来简化代码
fn print(result: Res<i32>) {
match result {
Ok(n) => println!("n is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
print(multiply("10", "2"));
print(multiply("t", "2"));
println!("Success!")
}
map and_then
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
let a = n1_str.parse::<i32>()?;
let b = n2_str.parse::<i32>()?;
Ok(a*b)
// n1_str.parse::<i32>().and_then(|n1| {
// n2_str.parse::<i32>().map(|n2| n1 * n2)
// })
}
生命周期

demo
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&'a self) -> i32 {
3
}
}
fn main() {}
可以省略生命周期的几个例子
fn nput(x: &i32) {
println!("`annotated_input`: {}", x);
}
fn pass(x: &i32) -> &i32 { x }
fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
x
}
struct Owner(i32);
impl Owner {
// Annotate lifetimes as in a standalone function.
fn add_one(&mut self) { self.0 += 1; }
fn print(&self) {
println!("`print`: {}", self.0);
}
}
struct Person<'a> {
age: u8,
name: &'a str,
}
enum Either<'a> {
Num(i32),
Ref(&'a i32),
}
fn main() {}