rust 第一个程序

wxvirus2022年9月17日大约 4 分钟

rust 第一个程序

词汇

  • struct/structure: 结构体
  • enum: 枚举
  • variable: 变量
  • constant: 常量
  • static: 静态变量
  • function:函数
  • method:方法
  • generics:泛型
  • trait:特征、特质
  • trait bound:特征约束、trait 约束

第一个 rust 代码

fn main() {
	println!("hi wxvirus")
}

这里的println!,是一个宏

使用rustc进行编译

➜  rustworkspace rustc main.rs
➜  rustworkspace ./main
hi wxvirus
➜  rustworkspace

安装源码

rustup component add rust-src

然后使用vs code安装一些插件,重新打开上述文件目录,就可以点击进入println!这个宏里面去查看源码了。

第一个比较正常的程序

使用cargo new scrape_url生成一个新项目,入口在src/main.rs,我们可以再Cargo.toml文件里加入项目依赖

[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
html2md = "0.2"

Cargo.toml 是 Rust 项目的配置管理文件,我们添加了 2 个依赖,reqwestopen in new window 是一个 HTTP 客户端,它的使用方式和 Python 下的 request 类似;html2md 顾名思义,把 HTML 文本转换成 Markdown。

src/main.rs编写代码

use std::fs;

fn main() {
  let url = "https://www.rust-lang.org/";
  let output = "rust.md";

  println!("Fetching url: {}", url);
  let body = reqwest::blocking::get(url).unwrap().text().unwrap();

  println!("Converting html to markdown...");
  let md = html2md::parse_html(&body);

  fs::write(output, md.as_bytes()).unwrap();
  println!("Converted markdown has been saved in {}.", output);
}

保存后,在命令行下执行cargo build && cargo run在漫长的编译后,程序开始运行,就会看到如下输出:

Fetching url: https://www.rust-lang.org/
Converting html to markdown...
Converted markdown has been saved in rust.md.

还会附带生成一个rust.md文件,这个就是将rust官网的html转换为了一个markdown文件。


基础类型和一些练习

use std::fs;

fn apply(value: i32, f: fn(i32) -> i32) -> i32 {
    f(value)
}

fn square(value: i32) -> i32 {
    value * value
}

fn cube(value: i32) -> i32 {
    value * value * value
}

fn pi() -> f64 {
    3.141592653
}

fn not_pi() {
    3.1415;
}

fn main() {
    let url = "https://www.rust-lang.org/";
    let output = "rust.md";

    println!("Fetching url: {}", url);
    let body = reqwest::blocking::get(url).unwrap().text().unwrap();

    println!("Converting html to markdown");
    let md = html2md::parse_html(&body);

    fs::write(output, md.as_bytes()).unwrap();
    println!("Converted to Markdown: {}", output);

    println!("apply square: {}", apply(2, square));
    println!("apply cube: {}", apply(2, cube));

    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
    );
}

➜  scrape_url git:(master) ✗ cargo build && cargo run
   Compiling scrape_url v0.1.0 (/Users/wujie/workspace/rustworkspace/scrape_url)
    Finished dev [unoptimized + debuginfo] target(s) in 0.53s
    Finished dev [unoptimized + debuginfo] target(s) in 0.06s
     Running `target/debug/scrape_url`
Fetching url: https://www.rust-lang.org/
Converting html to markdown
Converted to Markdown: rust.md
apply square: 4
apply cube: 8
is_pi: 3.141592653, is_unit1: (), is_unit2: ()

数据结构

数据结构是程序的核心组成部分,在对复杂的问题进行建模时,我们就要自定义数据结构。Rust 非常强大,可以用 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
    );
}

变量函数和结构体

变量

定义

  • 不可变:let x: T;
  • 可变:let mut x: T;

说明

在栈上分配一个类型为 T 的变量,变量名为x。当声明为可变变量时,x的内容可以被修改,且允许可变引用

示例
let name = "wujie";
let pi = 3.141592654;

let mut v: Vec<u8> = Vec::new();

常量

定义

const X: T = <value>;

常量是一个右值(rvalue),它不能被修改。常量编译后放入可执行文件的数据段,全局可以访问。

示例
const PI: f64 = 3.141592654;

静态变量

定义

static X: T = T::new();
static mut X: T = T::new();

静态变量和常量一样全局可以访问,它也被编入可执行文件的数据段中。静态变量可以被声明为可变。

提示

在使用静态变量时,由于一些限制,lazy_static是一个很好的工具。

示例
// 可以编译通过
static V: Vec<u8> = Vec::new();

// 无法编译通过,需要使用 lazy_static
static MAP: HashMap<String, String> = HashMap::new();

函数

定义

fn x(a1: T1, ...) -> T {}

Rust中,函数如果没有返回值,那么其返回值为unit,符号是()

fn valid_email(input: &str) -> bool {
    // ...
}

结构体

定义

struct s {...}

结构体有三种形式:

  1. 空结构体,不占任何内存空间
  2. 元组结构体,struct的每个域都是匿名的,可以通过索引访问
  3. 普通结构体,struct的每个域都有名字,可以通过名称访问
struct Marker;

struct Color(u8, u8, u8);

struct Person {
    name: String,
    age: u8,
}

enum

enum E {...}

enum有两种形式:

  1. 标签联合,enum可以承载多个不同的数据结构中的一种
  2. 枚举
enum Option<T> {
    Some(T),
    None,
}

enum Status {
    Ok = 0,
    BadName = 1,
    NotFound = 2,
    // ...
}
Loading...