生成第一个rust项目
目标:通过 HTTP 请求 Rust 官网首页,然后把获得的 HTML 转换成Markdown 保存起来。
步骤:
1.生成一个新项目
运行cargo new http_client命令生成一个新项目。默认情况下,这条命令会生成一个可执行项目http_client,入口在src/main.rs
2.配置依赖。
在Cargo.toml文件添加依赖
[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
html2md = "0.2"
注:Cargo.toml是rust项目的配置管理文件。reqwest和html2md是添加的2个依赖,reqwest是一个http客户端,html2md是把html转成Markdown。
3.添加代码
use std::fs
fn main() {
let url = "https://www.rust-lang.org/"
let output = "rust.md;
let body = reqwest::blocking::get(url).unwrap().text().unwrap();
let md = html2md::parse_html(&body);
fs::write(output, md_as_bytes()).unwwrap();
4.编译运行
运行cargo run
基本语法介绍
类似C++写法:
- 函数体用{}包裹
- 表达式之间用;分割
- 访问结构体成员或者变量使用.运算符
- 访问命名空间或者对象的静态函数使用::运算符
- 如果要简化对命名空间或者数据类型的使用,可以使用use关键字
- 入口函数是main()
其他特点 - 变量默认不可变的,如果要修改变量的值,需要显式的使用mut关键字
- 除了let/static/const/fn等少数语句外,rust大多数代码都是表达式。所以if/while/for/loop都会返回一个值,函数最后一个表达式就是函数的返回值
- rust支持面向接口编程和泛型编程
- rust有丰富的数据类型和强大的标准库
- rust有丰富的流程控制,包括模式匹配(pattern match)
rust开发基本内容
基本语法和基础数据类型
定义变量
- 定义不可变变量(如果修改变量值,编译器会报错)
let 变量名 = 值; - 定义可修改的变量(如果定义的值没有被修改,编译器会报警告)
let mut 变量名 = 值;
注:变量类型会自动推导,但是常量const和静态变量static必须声明类型。
定义函数
fn apply(value: i32) -> i32 {
return value * value;
}
参数的类型和返回值的类型都必须显式定义,如果没有返回值可以省略,返回类型unit。函数内部如果提前返回,需要用return关键字,否则最后一个表达式就是返回值。如果最后一个表达式添加了;分号,隐含返回值为unit。
fn apply(f: fn(i32) -> i32) -> i32 {
f(value)
}
第二个参数表明接受一个函数作为参数,参数只有一个,类型为i32,返回值类型也是i32
数据结构
可以用struct定义结构体,用enum定义联合体,也能随手定义元组类型
//标准的枚举
#[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);
}
控制流程
循环
支持死循环loop,条件循环while,迭代器循环for 循环可以通过break提前终止,或者continue跳到下一轮循环。
跳转
支持分支跳转、模式匹配、错误跳转、异步跳转
- 分支跳转就是if/else
- 模式匹配可以通过匹配表或者值的部分内容,进行分支跳转
- 在错误跳转中,当调用的函数返回错误时,rust会提前终止当前函数的执行,向上一层返回错误。
- 异步跳转,当async函数执行await时,程序当前上下文可能被阻塞,执行流程会跳转到另一个异步任务执行,直到await不再阻塞。
//斐波那契
fn fib_loop(n: u8) {
let mut a = 1;
let mut b = 1;
let mut i = 2u8;
loop {
let c = a + b;
a = b;
b = c;
i += 1;
if i >= n {
break;
}
}
}
fn fib_while(n: u8) {
let mut a = 1;
let mut b = 1;
let mut i = 2u8;
while i < n {
let c = a + b;
a = b;
b = c;
i += 1;
if i >= n {
break;
}
}
}
fn fib_for(n: u8) {
let mut a = 1;
let mut b = 1;
//2..n包含2 <= x < n的所有值
for _i in 2..n {
let c = a + b;
a = b;
b = c;
}
}
模式匹配
fn process_event(event: &Event) {
match event {
Event::Join((uid, _tid)) => println!("user {:?}", uid),
Event::Leave((uid, tid)) => println!("user {:?} tid {:?}", uid, tid),
Event::Message((_, _, msg)) => println!("message {}", msg),
}
}
主要学习于极客时间:rust编程第一课-陈天