// 使用 // 进行单行注释
//
// 也可以使用 /* */ 来进行块注释
/* */
// 使用 /// 来进行文档注释
///
fn main() {
// format! 返回一个字符串 String类型的变量
let name = vec!["Peter", "Trunph", "James"];
// 并且,我们可以使用位置参数来进行格式化输出
// 这将所有的后续输出数据当作一个数组使用
// 如下例,将name[0], name[1], name[2] 视为一个数组
// 则 {0} 表示这个数组的索引 0 的值,也就是 name[0]
// 当然 {}内也可以不指定索引,则其默认从 0 开始,并且递增
let str1 = format!("{0}-{1}-{2}", name[0], name[1], name[2]);
let str2 = format!("{}-{}-{}", name[0], name[1], name[2]);
println!("{}", str1);
println!("{}", str2);
println!("****************************");
// 并且, format还可以传递同作用域的变量
// 如果在其参数列表中存在相同名字的数据,则优先使用参数列表
let people = "Rustaceans";
let disv1 = format!("Hello {people}!");
let disv2 = format!("Hello {people}!", people = "Killer");
println!("{}", disv1);
println!("{}", disv2);
println!("****************************");
// println! 将文本输出到终端( print!和其作用相同,只不过该宏不进行换行)
print!("我不换行了--");
println!("我得换个行--");
println!("****************************");
// 我们在 format说明时使用了位置参数进行数据的传递
// 除了位置参数,还可以使用命名参数
println!(
"{subject} {verb} {object}",
object = "the lazy dog",
subject = "the quick brown fox",
verb = "jumps over"
);
println!("****************************");
// 那么如何进行其他格式化的输出呢,比如进制转换,对齐,保留小数点等
// 可以在 `:` 后面指定特殊的格式。
// {:b} 表示把传入的数据转换为二进制输出,看下面这个栗子
// 它把 2 转换为二进制 10 进行输出
println!("{} of {:b} people know binary, the other half don't", 1, 2);
println!("****************************");
// 你可以按指定宽度来右对齐文本。
// 下面语句输出 " 1",5 个空格后面连着 1。
// 同理,你也可以左对齐文本
println!("{number:, number = 1, width = 6);
println!("{number:>width$}", number = 1, width = 6);
println!("****************************");
// 并且你可以使用符号 0 来让 0 占有空位置
// 注意这是在左边补 0 ,和左对齐右对齐无关
println!("{number:>0width$}", number = 1, width = 6);
println!("{number:<0width$}", number = 1, width = 6);
println!("****************************");
// 更简便的,你可以不使用命名参数,直接使用如下方式
// 这表示共计占有 4 位宽度,左边用 0 补齐
println!("{:04}", 5);
println!("****************************");
// 保留特定位小数点
let pi = 3.141592;
// 我们想让 pi 保留三位小数点输出
// 方式如下:冒号前面的是位置参数,他代表参数中的索引 0
// 冒号后面我们使用一个 . ,再加上要保留的位数即可
// {0:.3} 表示保留三位小数点
println!("Pi is roughly {0:.3}", pi);
println!("****************************");
// 还有另外一种使用位置参数来定义位数的
// 这代表使用参数索引 1 的值来作为宽度
// 并且,默认的数据索引可以省略不写
println!("{:1$}", 0, 2);
println!("****************************");
// 使用命名参数的表示方法同理
println!("{:>width$}", 10, width = 6);
println!("****************************");
// 最后我们看一下本节的习题
// 用一个 println! 宏,通过控制显示的小数位数来打印:Pi is roughly 3.142
//(Pi 约等于 3.142)。为了达到练习目的,使用 let pi = 3.141592 作为 Pi 的近似值
// 其实我们在上面已经实现了,不妨再做一遍加深印象
let pi = 3.141592;
println!("Pi is roughly {0:.3}", pi);
// 本节练习地址
// https://rustwiki.org/zh-CN/rust-by-example/hello/print.html
// 出去上述说明的格式化方式,还有许多其他的格式化方式
// 如输出 0x55这种十六进制格式的方式等等,以及重要的 debug方式
// 可以到下面的官方标准库网站进行查阅
// https://rustwiki.org/zh-CN/std/fmt/
}
#[derive(Debug)]
enum Gender {
Male,
Female,
}
#[derive(Debug)]
struct Student {
grade: f64,
height: u32,
gender: Gender,
hobby: String,
}
fn main() {
// 并不是所有的类型都能够使用std::fmt的格式进行打印
// 想要能够进行这样的打印,需要实现一个可以打印的 trait
// 那么我们该如何输出那些不能进行 fmt::Display的类型呢
// 答案就是使用fmt::Debug进行实现
// 我们需要导入一个 Attribute,就是 derive 这个属性
// 他会对标签进行自动的推导
// 我们在程序外部导入 derive 对 fmt::Debug 进行自动推导
// 然后我们定义一个结构体 Student,并且进行实例化
let peter = Student {
grade: 95.0,
height: 175,
gender: Gender::Male,
hobby: String::from("Play LOL"),
};
let jane = Student {
grade: 94.5,
height: 165,
gender: Gender::Female,
hobby: String::from("Reading"),
};
// 下面我们使用 printt!宏来打印 这两个实例
// 我们会发现他并不能进行打印,因为他没有实现 Display
// println!("{}, {}", peter, jane);
// 下面我们使用 Debug的方式进行打印
println!("{:#?}\n{:#?}", peter, jane);
// 输出信息如下
/*
Student {
grade: 95.0,
height: 175,
gender: Male,
hobby: "Play LOL",
}
Student {
grade: 94.5,
height: 165,
gender: Female,
hobby: "Reading",
}
*/
}
use std::fmt;
#[derive(Debug)]
enum Gender {
Male,
Female,
}
// 为 Gender实现一个方法,这个方法可以被调用返回他的字符串切片
impl Gender {
fn get_str(&self) -> &str {
match *self {
Gender::Male => "Male",
Gender::Female => "Female",
}
}
}
#[derive(Debug)]
struct Student {
grade: f64,
height: u32,
gender: Gender,
hobby: String,
}
// 为 Student实现 Display
impl fmt::Display for Student {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"grade is {}, height is {}, gender is {}, hobby is {}",
self.grade,
self.height,
self.gender.get_str(),
self.hobby
)
}
}
// 习题练习
#[derive(Debug)]
struct Point2D {
x: f64,
y: f64,
}
// 对 `Point2D` 实现 `Display`
impl fmt::Display for Point2D {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// 自定义格式,使得仅显示 `x` 和 `y` 的值。
write!(f, "{} + {}i", self.x, self.y)
}
}
fn main() {
// 在 1.2.1 中,我们使用 derive 属性对 Debug 进行推导进行打印
// 但是它不够简洁,我们可以自己来实现 fmt::Display方法
// 首先引入fmt模块
// 然后我们把上个例子的结构体拿过来
// 之后,我们为 struct和 enum实现 Display这个 trait
// 见上方的实现
// 定义完成后,我们来打印一下
let peter = Student {
grade: 95.0,
height: 175,
gender: Gender::Male,
hobby: String::from("Play LOL"),
};
let jane = Student {
grade: 94.5,
height: 165,
gender: Gender::Female,
hobby: String::from("Reading"),
};
println!("{}", peter);
println!("{}", jane);
println!("{:#?}", peter);
println!("{:#?}", jane);
// 打印结果如下,可见,我们成功为struct实现了Display这个trait
/*
grade is 95, height is 175, gender is Male, hobby is Play LOL
grade is 94.5, height is 165, gender is Female, hobby is Reading
Student {
grade: 95.0,
height: 175,
gender: Male,
hobby: "Play LOL",
}
Student {
grade: 94.5,
height: 165,
gender: Female,
hobby: "Reading",
}
*/
// 可以看到,我们自己实现的Display和 Debug的输出方式明显不同
// 最后我们来看一下这一节的习题
let point = Point2D {
x: 3.3, y: 7.2 };
// 使用我们定义的 Display打印
println!("{}", point);
// 使用Debug打印
println!("{:#?}", point);
// 输出结果如下,目标完成
/*
3.3 + 7.2i
Point2D {
x: 3.3,
y: 7.2,
}
*/
}
use ::std::fmt;
// 定义一个元组结构体
struct List(Vec<i32>);
// 为其实现Display这个trait
// impl fmt::Display for List {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// let vec = &self.0;
// write!(f, "[")?;
// for (count, item) in vec.iter().enumerate() {
// if count != 0 {
// write!(f, ", ")?;
// }
// write!(f, "{}", item)?;
// }
// write!(f, "]")
// }
// }
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let vec = &self.0;
write!(f, "[")?;
for (count, item) in vec.iter().enumerate() {
if count != 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", count, item)?;
}
write!(f, "]")
}
}
fn main() {
// 这节来学习一下 ?符号的使用
// ? 操作符会自动进行match匹配,如果错误则会返回,没有错误则继续
let v = List(vec![1, 2, 3]);
println!("{}", v);
// 输出如下
// [1, 2, 3]
// 可见,使用 ? 可以省略我们很多的重复语句
// 下面我们来看一下本节的习题
//更改程序使 vector 里面每个元素的下标也能够打印出来。新的结果如下:
//[0: 1, 1: 2, 2: 3]
// 我们先将之前的注释掉
// 改完之后,输出一下试试
println!("{}", v);
// 结果如下
// [0: 1, 1: 2, 2: 3]
// 目标达成
}
use std::fmt::{
self, Display};
// 定义一个结构体
struct City {
name: &'static str,
lat: f32,
lon: f32,
}
struct Color {
red: u8,
green: u8,
blue: u8,
}
// 为City实现Display
impl Display for City {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let lac_c = if self.lat > 0.0 {
'N' } else {
'S' };
let lon_c = if self.lon > 0.0 {
'E' } else {
'W' };
write!(
f,
"{}: {:3}°{} {:3}°{}",
self.name,
self.lat.abs(),
lac_c,
self.lon.abs(),
lon_c
)
}
}
// 习题:为Color实现Display
impl Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"RGB ({0}, {1}, {2}) 0x{0:02X}{1:02X}{2:02X}",
self.red, self.green, self.blue
)
}
}
fn main() {
// 之前我们介绍format!等宏时说到
// 在 {} 中加入 :param 可以改变输出的格式
// 这个功能是使用 trait来实现的
// 下面我们来自己实现一下这个trait
for city in [
City {
name: "Dublin",
lat: 53.347778,
lon: -6.259722,
},
City {
name: "Oslo",
lat: 59.95,
lon: 10.75,
},
City {
name: "Vancouver",
lat: 49.25,
lon: -123.1,
},
]
.iter()
{
println!("{}", *city);
}
// 输出结果如下
// Dublin: 53.34778°N 6.259722°W
// Oslo: 59.95°N 10.75°E
// Vancouver: 49.25°N 123.1°W
// 下面我们来看一下本节习题
// 为上面的 Color 结构体实现 fmt::Display,应得到如下的输出结果:
// RGB (128, 255, 90) 0x80FF5A
// RGB (0, 3, 254) 0x0003FE
// RGB (0, 0, 0) 0x000000
for color in [
Color {
red: 128,
green: 255,
blue: 90,
},
Color {
red: 0,
green: 3,
blue: 254,
},
Color {
red: 0,
green: 0,
blue: 0,
},
]
.iter()
{
// 在添加了针对 fmt::Display 的实现后,请改用 {} 检验效果。
println!("{}", *color)
}
// 结果如下
/*
RGB (128, 255, 90) 0x80FF5A
RGB (0, 3, 254) 0x0003FE
RGB (0, 0, 0) 0x000000
*/
// 任务完成
// 虽然我们任务完成了,但是离我们开头说的实现{:param}这种实现形式
// 还是差了很多,那么我们怎么实现这种格式的输出呢
// 首先我们定义一个结构体,它表示一个浮点数 x.y
// x是他的整数部分,y是他的小数部分,并且我们要求它能够实现
// {:param}可以指定它小数输出部分的位数
// 下面我们来实现它
let flo = Flo {
x: 18, y: 52 };
println!("{:10.04}", flo);
// 我们要求是将flo结构体中的x作为整数,y作为小数
// 合并成一个数进行输出,并且可以指定小数的位数
// 上述例子将会输出 18.5200
// 示例成功
// 读者如果想要实现其他不同的功能与输出方式
// 请阅读 https://rustwiki.org/zh-CN/std/fmt/#formatting-traits
// 来寻找自己想要的方法,博主才疏学浅,就不过多说明了
}
struct Flo {
x: i32,
y: u32,
}
impl fmt::Display for Flo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let num: f64 = format!("{}.{}", self.x, self.y).parse().unwrap();
let decimals = f.precision().unwrap_or(3);
let string = format!("{:.*}", decimals, num);
f.pad_integral(true, "", &string)
}
}
fn main() {
// Rust中的那些原生类型
// 标量类型
// 有符号整数
let itype1: i8 = 8;
let itype2: i16 = 16;
let itype3: i32 = 32;
let itype4: i64 = 64;
let itype5: i128 = 128;
let itype6: isize = 64; // 指针宽度,32位或64位
// 无符号整数
let utype1: u8 = 8;
let utype2: u16 = 16;
let utype3: u32 = 32;
let utype4: u64 = 64;
let utype5: u128 = 128;
let utype6: usize = 64; // 指针宽度,32位或64位
// 也可以使用后缀声明变量类型
let utype_suffix = 50i32;
// 浮点数
let ftype1: f32 = 32.00;
let ftype2: f64 = 64.00;
// 布尔型
let bool_type: bool = true; // true or false
// 单元类型:空元组
let unit_type = ();
// 复合类型
// 数组
let array_type = [1, 2, 3, 4, 5];
// 元组
let tuple_type = (1, 2, 3, 4, 5);
// 定义一个变量时,如果不显示声明变量的可变性,则变量默认不可变
// 使用mut来使变量可变
let mut mutable = 56;
// 变量的值可以改变,但是变量的类型不能改变
// 但是你可以使用shadow来遮蔽前面的变量
// mutable = true;
let mutable = true;
}
fn main() {
// 整数相加
println!("1 + 2 = {}", 1u32 + 2);
// 整数相减
println!("1 - 2 = {}", 1i32 - 2);
// 试一试 ^ 尝试将 `1i32` 改为 `1u32`,体会为什么类型声明这么重要
// 短路求值的布尔逻辑
println!("true AND false is {}", true && false);
println!("true OR false is {}", true || false);
println!("NOT true is {}", !true);
// 位运算
println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
println!("1 << 5 is {}", 1u32 << 5);
println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);
// 使用下划线改善数字的可读性!
println!("One million is written as {}", 1_000_000u32);
}
use std::fmt;
// 元组可以充当函数的参数和返回值
fn reverse(pair: (i32, bool)) -> (bool, i32) {
// 可以使用 `let` 把一个元组的成员绑定到一些变量
let (integer, boolean) = pair;
(boolean, integer)
}
// 在练习中要用到下面这个结构体。
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
fn main() {
// 包含各种不同类型的元组
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64