Rust 笔记
https://rustwiki.org/zh-CN/rust-by-example/custom_types/constants.html
1 print!
- fmt::Debug:使用 {:?} 标记。格式化文本以供调试使用。需要 #[derive(Debug)]
可以使用 {:#?} 来获得更规范的数据结构的打印 - fmt::Display:使用 {} 标记。以更优雅和友好的风格来格式化文本
println!("Pi is roughly {:.3}", pi);
#[derive(Debug)]
struct Complex {
real: f64,
imag: f64,
}
impl fmt::Display for Complex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}i", self.real, self.imag)
}
}
println!("Display: {}", complex);
println!("Debug: {:?}", complex)
impl Display for Color {
// RGB (0, 3, 254) 0x0003FE
// TODO: use for loop to print three properties
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "RGB ({}, {}, {}) 0x{:02X}{:02X}{:02X}",
self.red, self.green, self.blue, self.red, self.green, self.blue)
}
}
2 变量
实在无法推断类型时,按 i32/f64 使用
use std::fmt;
use std::fmt::Formatter;
// 元组可以充当函数的参数和返回值
fn reverse(pair: (i32, bool)) -> (bool, i32) {
// 可以使用 `let` 把一个元组的成员绑定到一些变量
let (integer, boolean) = pair;
(boolean, integer)
}
// 在 “动手试一试” 的练习中要用到下面这个结构体。
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
impl fmt::Display for Matrix {
// ( 1.1 1.2 )
// ( 2.1 2.2 )
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "( {} {} )\n", self.0, self.1)?;
write!(f, "( {} {} )", self.2, self.3)
}
}
fn transpose(old: Matrix) -> Matrix {
Matrix(old.0, old.2, old.1, old.3)
}
fn main() {
// 包含各种不同类型的元组
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64,
'a', true);
// 通过元组的下标来访问具体的值
println!("long tuple first value: {}", long_tuple.0);
println!("long tuple second value: {}", long_tuple.1);
// 元组也可以充当元组的元素
let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);
// 元组可以打印
println!("tuple of tuples: {:?}", tuple_of_tuples);
// 但很长的元组无法打印
// let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
// println!("too long tuple: {:?}", too_long_tuple);
// 试一试 ^ 取消上面两行的注释,阅读编译器给出的错误信息。
let pair = (1, true);
println!("pair is {:?}", pair);
println!("the reversed pair is {:?}", reverse(pair));
// 创建单元素元组需要一个额外的逗号,这是为了和被括号包含的字面量作区分。
println!("one element tuple: {:?}", (5u32,));
println!("just an integer: {:?}", (5u32));
// 元组可以被解构(deconstruct),从而将值绑定给变量
let tuple = (1, "hello", 4.5, true);
let (a, b, c, d) = tuple;
println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
println!("debug: {:?}", matrix);
println!("display: \n{}", matrix);
println!("Matrix:\n{}", matrix);
println!("Transpose:\n{}", transpose(matrix));
}
元组 (, , )
数组的类型标记为 [T; size]
切片是一个双字 对象(two-word object),第一个字是一个指向数据的指针,第二个字是切片的长度。
Rust 自定义数据类型主要是通过下面这两个关键字来创建:
struct: 定义一个结构体(structure)
enum: 定义一个枚举类型(enumeration)
而常量(constant)可以通过 const 和 static 关键字来创建。
#[derive(Debug)]
struct Person<'a> {
name: &'a str,
age: u8,
}
// 单元结构体
struct Nil;
// 元组结构体
struct Pair(i32, f32);
#[derive(Debug)]
// 带有两个字段(field)的结构体
struct Point {
x: f32,
y: f32,
}
// 结构体可以作为另一个结构体的字段
#[allow(dead_code)]
#[derive(Debug)]
struct Rectangle {
p1: Point,
p2: Point,
}
fn rect_area(rec: &Rectangle) -> f32 {
let Rectangle {
p1: Point { x: x1, y: y1},
p2: Point { x: x2, y: y2},
} = rec;
((x1-x2) * (y1-y2)).abs()
//((rec.p1.x-rec.p2.x) * (rec.p1.y-rec.p2.y)).abs
}
fn square(p: Point, len: f32) -> Rectangle {
Rectangle {
p1: Point { x: p.x, y: p.y len },
p2: Point { x: p.x len, y: p.y },
}
}
fn main() {
// 使用简单的写法初始化字段,并创建结构体
let name = "Peter";
let age = 27;
let peter = Person { name, age };
// 以 Debug 方式打印结构体
println!("{:?}", peter);
// 实例化结构体 `Point`
let point: Point = Point { x: 0.3, y: 0.4 };
// 访问 point 的字段
println!("point coordinates: ({}, {})", point.x, point.y);
// 使用结构体更新语法创建新的 point,这样可以用到之前的 point 的字段
let new_point = Point { x: 0.1, ..point };
// `new_point.y` 与 `point.y` 一样,因为这个字段就是从 `point` 中来的
println!("second point: ({}, {})", new_point.x, new_point.y);
// 使用 `let` 绑定来解构 point
let Point { x: my_x, y: my_y } = point;
let _rectangle = Rectangle {
// 结构体的实例化也是一个表达式
p1: Point { x: my_y, y: my_x },
p2: point,
};
// 实例化一个单元结构体
let _nil = Nil;
// 实例化一个元组结构体
let pair = Pair(1, 0.1);
// 访问元组结构体的字段
println!("pair contains {:?} and {:?}", pair.0, pair.1);
// 解构一个元组结构体
let Pair(integer, decimal) = pair;
println!("pair contains {:?} and {:?}", integer, decimal);
let r1 = Rectangle { p1: Point{x:1.0, y:2.0}, p2: Point{x:3.0, y:4.0} };
let r2 = Rectangle { p1: Point{x:3.0, y:2.0}, p2: Point{x:3.0, y:4.0} };
println!("the area of rectangle {:?} is {}", r1, rect_area(&r1));
println!("the area of rectangle {:?} is {}", r2, rect_area(&r2));
let p1 = Point{x:1.0, y:2.0};
let len = 3.3;
let s1 = square(p1, len);
println!("the area of rectangle {:?} is {}", s1, rect_area(&s1))
}
enum,match
类型别名 type Operations = VeryVerboseEnumOfThingsToDoWithNumbers,最常见的情况就是在 impl 块中使用 Self 别名。
Rust 有两种常量,可以在任意作用域声明,包括全局作用域。它们都需要显式的类型声明:
const:不可改变的值(通常使用这种)。
static:具有 'static 生命周期的,可以是可变的变量(译注:须使用 static mut 关键字)。
const 和 let 的区别:const 一定会被编译期计算,let 只会检查生命周期。
变量绑定:
- 变量名前面加下划线可以忽视未使用的警告
- 可以先声明再初始化,编译器会检查
类型系统:
- 基本类型不能隐式转换,可以使用
xxx as u8
进行显式转换。 - 整数间转换是直接切位
- 数值字面量可以直接把类型写在后面,没写就是 i32, f64;std::mem::size_of_val(&x) 类似于 sizeof
- 类型推导比较聪明,可以从后文推导
- 别名,
type a = b
.
类型转换
- From 和 Into,实现了 from 也就可以用 into
use std::convert::From;
#[derive(Debug)]
struct Number {
value: i32,
}
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
fn main() {
let num = Number::from(30);
println!("My number is {:?}", num);
}
fn main() {
let int = 5;
// 试试删除类型说明
let num: Number = int.into();
println!("My number is {:?}", num);
}
- tryFrom 和 tryInto,结果返回 result
- 没必要实现 ToString,可以直接实现 fmt::Display;
- 如果想调用 parse,可以实现 FromString
表达式
- rust 中最常用的语句有两种:1. 变量绑定(一定需要分号) 2. 表达式(可能跟着分号)
- 代码块也是表达式,值 = 最后执行的语句的值(如果最后执行的语句有分号,那么值是
()
)
流程
- if-else 语句也是表达式,条件不用小括号,代码块必须要大括号,所有分支返回类型必须相同
- 无限循环:loop {}
- 循环标签:
#![allow(unreachable_code)]
fn main() {
'outer: loop {
println!("Entered the outer loop");
'inner: loop {
println!("Entered the inner loop");
// 这只是中断内部的循环
//break;
// 这会中断外层循环
break 'outer;
}
println!("This point will never be reached");
}
println!("Exited the outer loop");
}
- break 后面可以跟着返回值
- while 循环
for in <iterator>
,比如for in 1..101
迭代器生成方式:- 1…101 左闭右开
- 1…=100 闭区间
- vec.into_iter() 默认方式,转变成 iter 并消耗
- vec.iter() 依次借用集合中的元素
- vec.mut_iter() 可变地借用集合中的元素
match
- match 匹配:解构,分支可以是
1|3|4
,也可以是3..20
&
取引用,*
解引用,let ref
获得引用- match 中,
&val
会匹配一个引用并解开,val 是一个值类型。而ref r
会匹配一个引用但不解开,r 是一个引用类型。
fn main() {
// 获得一个 `i32` 类型的引用。`&` 表示取引用。
let reference = &4;
match reference {
// 如果用 `&val` 这个模式去匹配 `reference`,就相当于做这样的比较:
// `&i32`(译注:即 `reference` 的类型)
// `&val`(译注:即用于匹配的模式)
// ^ 我们看到,如果去掉匹配的 `&`,`i32` 应当赋给 `val`。
// 译注:因此可用 `val` 表示被 `reference` 引用的值 4。
&val => println!("Got a value via destructuring: {:?}", val),
}
// 如果不想用 `&`,需要在匹配前解引用。
match *reference {
val => println!("Got a value via dereferencing: {:?}", val),
}
// 如果一开始就不用引用,会怎样? `reference` 是一个 `&` 类型,因为赋值语句
// 的右边已经是一个引用。但下面这个不是引用,因为右边不是。
let _not_a_reference = 3;
// Rust 对这种情况提供了 `ref`。它更改了赋值行为,从而可以对具体值创建引用。
// 下面这行将得到一个引用。
let ref _is_a_reference = 3;
// 相应地,定义两个非引用的变量,通过 `ref` 和 `ref mut` 仍可取得其引用。
let value = 5;
let mut mut_value = 6;
// 使用 `ref` 关键字来创建引用。
// 译注:下面的 r 是 `&i32` 类型,它像 `i32` 一样可以直接打印,因此用法上
// 似乎看不出什么区别。但读者可以把 `println!` 中的 `r` 改成 `*r`,仍然能
// 正常运行。前面例子中的 `println!` 里就不能是 `*val`,因为不能对整数解
// 引用。
match value {
ref r => println!("Got a reference to a value: {:?}", r),
}
// 类似地使用 `ref mut`。
match mut_value {
ref mut m => {
// 已经获得了 `mut_value` 的引用,先要解引用,才能改变它的值。
*m = 10;
println!("We added 10. `mut_value`: {:?}", m);
},
}
}
- match 可以加 if,这叫做 guard
match pair {
(x, y) if x == y => println!("These are twins"),
// ^ `if` 条件部分是一个卫语句
(x, y) if x y == 0 => println!("Antimatter, kaboom!"),
(x, _) if x % 2 == 1 => println!("The first one is odd"),
_ => println!("No correlation..."),
}
- 可以使用
@
边匹配边绑定
match age() {
0 => println!("I haven't celebrated my first birthday yet"),
// 可以直接匹配(`match`) 1 ..= 12,但那样的话孩子会是几岁?
// 相反,在 1 ..= 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。
n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
// 不符合上面的范围。返回结果。
n => println!("I'm an old person of age {:?}", n),
}
- match 需要覆盖全部情况,如果不想用
_
,可以使用if let
尝试解构
// 该枚举故意未注明 `#[derive(PartialEq)]`,
// 并且也没为其实现 `PartialEq`。这就是为什么下面比较 `Foo::Bar==a` 会失败的原因。
enum Foo {Bar}
fn main() {
let a = Foo::Bar;
// 变量匹配 Foo::Bar
// if Foo::Bar == a { // 编译错误,因为不能比较
if let Foo::Bar = a { //编译成功
println!("a is foobar");
}
}
- while let
fn main() {
// 将 `optional` 设为 `Option<i32>` 类型
let mut optional = Some(0);
// 这读作:当 `let` 将 `optional` 解构成 `Some(i)` 时,就
// 执行语句块(`{}`)。否则就 `break`。
while let Some(i) = optional {
if i > 9 {
println!("Greater than 9, quit!");
optional = None;
} else {
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i 1);
}
// ^ 使用的缩进更少,并且不用显式地处理失败情况。
}
// ^ `if let` 有可选的 `else`/`else if` 分句,
// 而 `while let` 没有。
}
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhhiggbh
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22