rust语法-1

121 阅读4分钟

生成第一个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++写法:

  1. 函数体用{}包裹
  2. 表达式之间用;分割
  3. 访问结构体成员或者变量使用.运算符
  4. 访问命名空间或者对象的静态函数使用::运算符
  5. 如果要简化对命名空间或者数据类型的使用,可以使用use关键字
  6. 入口函数是main()
    其他特点
  7. 变量默认不可变的,如果要修改变量的值,需要显式的使用mut关键字
  8. 除了let/static/const/fn等少数语句外,rust大多数代码都是表达式。所以if/while/for/loop都会返回一个值,函数最后一个表达式就是函数的返回值
  9. rust支持面向接口编程和泛型编程
  10. rust有丰富的数据类型和强大的标准库
  11. rust有丰富的流程控制,包括模式匹配(pattern match)

rust开发基本内容

image.png

基本语法和基础数据类型

定义变量

  1. 定义不可变变量(如果修改变量值,编译器会报错)
    let 变量名 = 值;
  2. 定义可修改的变量(如果定义的值没有被修改,编译器会报警告)
    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);
}

image.png

控制流程

循环

支持死循环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;
    }
} 

image.png

模式匹配

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编程第一课-陈天