Rust学习-基本语法
搭建Rust环境 1、安装Rust 使用rustup.rs中给出的方法,根据自身操作系统进行安装即可
2、 选择开发工具 选择一:Clion+插件形式 推荐插件: Rust: 提供Rust语言相支持
选择二:vscode+插件形式 推荐插件: rust-analyzer: 实时编译和分析Rust代码,提示代码中的错误,并对类型进行标注 rust syntax: 为代码提供语法高亮 crates: 帮助分析当前项目的依赖是否是最新版本 Even Better TOML: Rust使用toml做项目的配置管理,提供toml语法高亮及检查toml文件中的错误 rust test lens: 可以帮你快速运行某个Rust测试
变量和函数
Rust支持类型推导 在编译器能够推导类型的情况下,可以省略变量类型,但是常量和静态变量必须声明变量类型
let var1 = "var1"; // 没有显示指定变量的类型,编译器会自行进行推导
const CONST_VAL: &str = "const value"; // 常量必须声明变量类型
static STATIC_VAL: &str = "static value"; // 静态变量也必须声明变量类型
// 常量和静态变量不进行类型声明会报类型丢失的错误
// const NOT_DECLEAR: = ""; // Missing type for `const` item
Rust变量默认是不可变的 可以添加 mut 关键字让变量具备可变性。 当你使用 mut 却没有修改变量,Rust编译器会友好地提示你移除不必要的mut。
let immutable_name = "alice";
// immutable_name = "bob"; // Cannot assign twice to immutable variable [E0384]
let mut mutable_name = "andy";
mutable_name = "bob";
Rust变量命名 Rust变量支持英文、数字和下划线(_),且只能以下划线和英文开头 以下划线开头的变量,表示暂时未被使用的变量 Rust也支持使用非ASCII字符进行变量命名
Rust中的函数 在Rust下,函数是一等公民,可以作为参数或返回值
// apply函数有两个参数:一个是value类型是i32,
// 另一个是func类型是fn(i32) -> i32,它表明func参数接受一个函数作为参数,
// 这个传入参数必须满足:参数只有一个,且类型为i32,返回值类型也是i32
fn apply(value: i32, func: fn(i32) -> i32) -> i32 {
func(value)
}
fn square(value: i32) -> i32 {
value * value
}
fn cube(value: i32) -> i32 {
value * value * value
}
fn main (){
println!("apply square: {}", apply(2, square)); // apply square: 4
println!("apply square: {}", apply(2, cube)); // apply cube: 8
}
Rust参数和返回值 Rust函数参数的类型和返回值的类型都必须显式定义,如果没有返回值可以省略,返回 unit 类型 函数内部如果提前返回,需要用 return 关键字,否则最后一个表达式就是其返回值 如果最后一个表达式后添加了; 分号,隐含其返回值为 unit 类型
use std::f64::consts::PI;
fn pi() -> f64 {
PI
}
fn not_pi() {
PI;
}
fn main() {
let is_pi = pi();
let is_unit1 = not_pi();
let is_unit2 = {
pi();
};
println!("is_pi: {:?}, is_unit1: {:?}, is_unit2: {:?}", is_pi, is_unit1, is_unit2);
}
数据结构
用 struct 定义结构体,用 enum 定义标签联合(tagged union), 还可以像 Python 一样随手定义元组(tuple)类型。
#[derive(Debug)]
enum Gender {
Unspecified = 0,
Female = 1,
Male = 2,
}
#[derive(Debug, Copy, Clone)]
struct UserId(u64);
#[derive(Debug, Copy, Clone)]
struct TopicId(u64);
#[derive(Debug)]
struct User {
id: UserId,
name: String,
gender: Gender,
}
#[derive(Debug)]
struct Topic {
id: TopicId,
name: String,
owner: UserId,
}
// 定义聊天室中可能发生的事件
#[derive(Debug)]
enum Event {
Join((UserId, TopicId)),
Leave((UserId, TopicId)),
Message((UserId, TopicId, String)),
}
fn main() {
let alice = User { id: UserId(1), name: "Alice".into(), gender: Gender::Female };
let bob = User { id: UserId(2), name: "Bob".into(), gender: Gender::Male };
let topic = Topic { id: TopicId(1), name: "rust".into(), owner: UserId(1) };
let event1 = Event::Join((alice.id, topic.id));
let event2 = Event::Join((bob.id, topic.id));
let event3 = Event::Message((alice.id, topic.id, "Hello world!".into()));
println!("event1: {:?}, event2: {:?}, event3: {:?}", event1, event2, event3);
}
说明 1、Gender: 一个枚举类型,在Rust下,使用 enum 可以定义类似 C 的枚举类型
2、UserId/TopicId: struct 的特殊形式,称为元组结构体。它的域都是匿名的,可以用索引访问,适用于简单的结构体
3、User/Topic: 标准的结构体,可以把任何类型组合在结构体里使用
4、Event: 标准的标签联合体,它定义了三种事件:Join、Leave、Message。每种事件都有自己的数据结构
控制语句
条件语句
fn main () {
let age: i32 = 30_i32;
if age < 18 {
println!("teenager");
}else {
println!("adult");
}
}
循环语句 Rust 支持三种循环,分别是死循环loop,条件循环while,以及对迭代器的循环for 循环可以使用 break 提前终止,或者使用 continue 跳到下一轮循环 和 C 语言类似,循环支持打标签(不推荐使用)
fn main () {
let mut n: i32 = 5;
loop {
if n == 0 {
break;
}
print!("loop ");
n = n - 1;
}
println!();
for i in 0..5 {
print!("{} ", i);
}
println!();
n = 5;
while n != 0 {
print!("{} ", n);
n = n - 1;
}
}
模式匹配 match 关键字用于模式匹配,它可以匹配 struct/enum 中部分或者全部内容 可以直接对 enum 内层的数据进行匹配并赋值 可以使用 _ 符号进行缺省匹配
// 下面使用了 Debug派生宏 用于简化 struct/enum 输出
#[derive(Debug)]
struct CountryName (String);
#[derive(Debug)]
struct CountryRegion (String);
#[derive(Debug)]
struct OtherInfo {
population: f32,
}
#[derive(Debug)]
enum Country {
China(CountryName, CountryRegion, OtherInfo),
Japan(CountryName, CountryRegion, OtherInfo),
Canada(CountryName, CountryRegion, OtherInfo),
}
fn print_country_info(country: &Country){
match country{
Country::China(name, region, other_info) => {
println!("country name: {:?}, country region: {:?}, other info: {:?}", name, region, other_info);
},
Country::Japan(name, region, _) => {
println!("country name: {:?}, country region: {:?}", name, region);
},
Country::Canada(name, _, _) => {
println!("country name: {:?}", name);
}
};
}
fn main () {
let china = Country::China(CountryName("中国".into()), CountryRegion("亚洲".into()), OtherInfo{
population: 14.13_f32,
});
let japan = Country::Japan(CountryName("日本".into()), CountryRegion("亚洲".into()), OtherInfo{
population: 1.26_f32,
});
let canada = Country::Canada(CountryName("加拿大".into()), CountryRegion("北美洲".into()), OtherInfo{
population: 0.3820_f32,
});
// 输出:country name: CountryName("中国"), country region: CountryRegion("亚洲"), other info: OtherInfo { population: 14.13 }
print_country_info(&china);
// 输出:country name: CountryName("日本"), country region: CountryRegion("亚洲")
print_country_info(&japan);
// 输出:country name: CountryName("加拿大")
print_country_info(&canada);
}
错误处理
Rust 没有沿用 C++/Java 等语言使用的异常处理方式,而是借鉴 Haskell,把错误封装在 Result<T, E>类型中 同时提供了 ? 操作符来传播错误,Result<T, E> 类型是一个泛型数据结构,T 代表成功执行返回的结果类型,E 代表错误类型 ? 操作符只能用在返回类型为 Result<T, E> 和 Option<T> 的函数当中
// 在Cargo.toml 配置文件中的dependencies下添加如下依赖
// reqwest = {version = "0.11.0", features = ["blocking"] }
// html2md = "0.2.0"
use std::fs;
// main 函数现在返回一个 Result
fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = "https://www.rust-lang.org/";
let output = "rust.md";
println!("Fetching url: {}", url);
let body = reqwest::blocking::get(url)?.text()?;
println!("Converting html to markdown...");
let md = html2md::parse_html(&body);
fs::write(output, md.as_bytes())?;
println!("Converted markdown has been saved in {}.", output);
Ok(())
}