完成以下代码的运行,也就代表着基本了解Rust代码的运行逻辑,更代表自己的Rust开发环境已经正常。
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
println!("The secret number is:{secret_number}");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {guess}");
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small"),
Ordering::Greater=>println!("Too big"),
Ordering::Equal=>println!("You win"),
}
}
函数println!和print!,ln会输出字符串最后的换行符。
注意,Rust的占位符为{}
Rust是一门强类型语言,但是为了高并发安全所做的设计,存在可变与不可变变量。
使用let 进行赋值,加上关键字mut后成为可变变量
重影与可变变量的赋值不是一个概念,重影是指用同一个名字重新代表另一个变量实体,其类型、可变属性和值都可以变化。但可变变量赋值仅能发生值的变化。
()包含不同类型,[]包含相同类型
一般是//与/*……*/
为说明文档注释时使用///
fn <函数名> ( <参数> ) <函数体>
Rust不在乎何处定义函数,只需在某个地方定义它们即可。
注意Rust可以使用返回值进行定义,如下图这个例子:
fn main() {
let x = 5;
let y = {
let x = 3;
x + 1
};
println!("x 的值为 : {}", x);
println!("y 的值为 : {}", y);
}
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
if-else语句,条件必须为bool类型
loop 循环可以通过 break 关键字类似于 return 一样使整个循环退出并给予外部一个返回值。这是一个十分巧妙的设计,因为 loop 这样的循环常被用来当作查找工具使用,如果找到了某个东西当然要将这个结果交出去。
所有权是Rust特有的资源管理机制,与别的语言的非常不同,需要注意。
变量范围,与{}相关
{
char *s = strdup("runoob");
free(s); *// 释放 s 资源*
}
实际上Rust没有什么确切的内存释放,而是依靠着编译器自带的内存释放,这里就使用到Rust的特定的功能,即所有权的问题。
移动后会销毁签名那个变量,防止对值得二次销毁
多复制一份数据在堆里
类似C++的空指针,在Rust里就是所引用的值已经被销毁。
对数组或字符串数组进行的切片,即进行截取。
记住格式即可,与C/C++类似,但是Rust的结构体常常在面向对象里使用。
结构体类名 {
字段名 : 字段值,
...
}
Rust的枚举类较为复杂。
enum Book {
Papery(u32),
Electronic(String),
}
let book = Book::Papery(1001);
let ebook = Book::Electronic(String::from("url://..."));
类似于switch语法,但是有相应改进。
match 枚举类实例 {
分类1 => 返回值表达式,
分类2 => 返回值表达式,
...
}
Option 是 Rust 标准库中的枚举类,这个类用于填补 Rust 不支持 null 引用的空白。
只是区分两种情况的match语法糖
if let 匹配值 = 源变量 {
语句块
}
生命周期是与所有权同样重要的资源管理机制
生命周期注释是描述生命周期的发布方法
&i32 // 常规引用
&'a i32 // 含有生命周期注释的引用
&'a mut i32 // 可变型含有生命周期注释的引用
函数的生命周期声明是函数的入参和返回值的一种生命周期约定和限制。
当我们定义的struct的里面有对象引用的时候,我们需要在struct的模板参数中增加生命周期声明。
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
where T: Display
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
它是树状结构,存在于包中。
工程的实质就是一个包,包必须由Cargo.toml管理
Rust的组织单位是模块。
类似于Java的类,JavaScript组织模块方式为function。
mod nation {
mod government {
fn govern() {}
}
mod congress {
fn legislate() {}
}
mod court {
fn judicial() {}
}
}
在文件系统中,目录结构往往以斜杠在路径字符串中表示对象的位置,Rust 中的路径分隔符是 :: 。
路径分为绝对路径和相对路径。绝对路径从 crate 关键字开始描述。相对路径从 self 或 super 关键字或一个标识符开始描述。
Rust的访问权限:公共与私有。
使用use关键字可以将模块标识符引用当前作用域。
Rust有一套独特的错误处理机制
panic!
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
match f {
Ok(file) => {
println!("File opened successfully.");
},
Err(err) => {
println!("Failed to open the file.");
}
}
}
如果想使一个可恢复错误按不可恢复错误处理,Result 类提供了两个办法:unwrap() 和 expect(message: &str) :
kind函数可以获取Result的Err类型。
泛型是每一个编程语言必不可少的一部分。
C++使用模板来实现。
fn max(array: &[i32]) -> i32 {
let mut max_index = 0;
let mut i = 1;
while i < array.len() {
if array[i] > array[max_index] {
max_index = i;
}
i += 1;
}
array[max_index]
}
fn main() {
let a = [2, 4, 6, 3, 1];
println!("max = {}", max(&a));
}
结构体与枚举类都可以定义方法,那么方法也应该实现泛型的机制,否则泛型的类将无法被有效的方法操作。
特性的概念接近于Java中的接口,以及C++中的虚函数。
trait Descriptive {
fn describe(&self) -> String;
}
Rust 同一个类可以实现多个特性,每个 impl 块只能实现一个。
总之,使用struct定义成员变量,使用类定义成员方法。
在Rust中可以用模块实现最外层的封装,每一个Rust都可以作为一个模块,模块内的天涯不属于可以通过pub对外明示。
“类”是面向对象编程常常用到的概念。“类”封装的是数据
在 Rust 中,我们可以使用结构体或枚举类来实现类的功能:
pub struct ClassName {
pub field: Type,
}
pub impl ClassName {
fn some_method(&self) {
// 方法函数体
}
}
pub enum EnumName {
A,
B,
}
pub impl EnumName {
fn some_method(&self) {
}
}
Rust 没有提供跟继承有关的语法糖,也没有官方的继承手段(完全等同于 Java 中的类的继承),但灵活的语法依然可以实现相关的功能。
环境参数需要std::env取出
fn main() {
let args = std::env::args();
println!("{:?}", args);
}
读取文本文件:
use std::fs;
fn main() {
let text = fs::read_to_string("D:\\text.txt").unwrap();
println!("{}", text);
}
读取二进制文件:
use std::fs;
fn main() {
let content = fs::read("D:\\text.txt").unwrap();
println!("{:?}", content);
}
文件流读取方式:
use std::io::prelude::*;
use std::fs;
fn main() {
let mut buffer = [0u8; 5];
let mut file = fs::File::open("D:\\text.txt").unwrap();
file.read(&mut buffer).unwrap();
println!("{:?}", buffer);
file.read(&mut buffer).unwrap();
println!("{:?}", buffer);
}
std::fs 模块中的 File 类是描述文件的类,可以用于打开文件,再打开文件之后,我们可以使用 File 的 read 方法按流读取文件的下面一些字节到缓冲区(缓冲区是一个 u8 数组),读取的字节数等于缓冲区的长度。
一次性写入:
use std::fs;
fn main() {
fs::write("D:\\text.txt", "FROM RUST PROGRAM")
.unwrap();
}
流写入:
use std::io::prelude::*;
use std::fs::File;
fn main() {
let mut file = File::create("D:\\text.txt").unwrap();
file.write(b"FROM RUST PROGRAM").unwrap();
}
集合是数据结构中最普遍的数据存放形式。
向量(Vector)是一个存放多值的单数据结构,该结构将相同类型的值线性的存放在内存中。
向量是线性表,在 Rust 中的表示是 Vec。
向量的使用方式类似于列表(List),我们可以通过这种方式创建指定类型的向量:
let vector: Vec<i32> = Vec::new(); // 创建类型为 i32 的空向量
let vector = vec![1, 2, 4, 8]; // 通过数组创建向量
常用方法:
append将一个向量拼接到另一个向量尾部
get方法取出向量的值(同样可以使用数组表示法)
常用函数:
let mut s = String::from("run");
s.push_str("oob"); // 追加字符串切片
s.push('!'); // 追加字符
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = s1 + "-" + &s2 + "-" + &s3;
//求字符长度
let s = "hello";
let len = s.len();
// 因为中文每个字符长3字节。统计字符数量应该先统计字符集合
let s = "hello你好";
let len = s.chars().count();
//遍历字符串
fn main() {
let s = String::from("hello中文");
for c in s.chars() {
println!("{}", c);
}
}
//从字符串中取出单个字符
fn main() {
let s = String::from("EN中文");
let a = s.chars().nth(2);
println!("{:?}", a);
}
//注意,nth不能用在遍历中
//注意截取字符串时必须特别注意UTF-8字符,以下程序会报错
fn main() {
let s = String::from("EN中文");
let sub = &s[0..3];
println!("{}", sub);
}
映射表(Map)在其他语言中广泛存在。其中应用最普遍的就是键值散列映射表(Hash Map)。
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("color", "red");
map.insert("size", "10 m^2");
println!("{}", map.get("color").unwrap());
}