返回

Rust全栈开发——带实例的完整教程:从基础到精通

后端

Rust全栈开发——带实例的完整教程

Rust是一种多范式系统编程语言,以其安全性、性能和可靠性而著称。近年来,Rust在Web开发领域也越来越受欢迎,因为它可以构建高性能、安全可靠的Web服务和应用程序。

本教程将指导您使用Rust构建一个完整的Web应用,从后端到前端,涵盖Rust网络服务、Rust前端应用、Rust CRUD操作、Rust Yew、Rust Warp、Rust Rocket等内容。

先决条件

在开始本教程之前,您需要确保已经安装了以下软件:

  • Rust
  • Cargo
  • Node.js
  • npm

项目结构

我们的项目结构如下:

├── backend
│   ├── Cargo.toml
│   ├── src
│   │   ├── main.rs
│   │   ├── routes.rs
│   │   ├── models.rs
│   │   ├── db.rs
│   └── package.json
├── frontend
│   ├── Cargo.toml
│   ├── src
│   │   ├── main.rs
│   │   ├── components
│   │   │   ├── todo_list.rs
│   │   │   ├── todo_item.rs
│   │   │   ├── add_todo.rs
│   │   │   └── filter_todos.rs
│   │   ├── pages
│   │   │   ├── home.rs
│   │   │   ├── todos.rs
│   │   │   └── not_found.rs
│   │   ├── App.js
│   │   ├── index.html
│   │   └── package.json
└── package.json

后端

后端使用Rust编写,并使用Warp框架构建Web服务。

安装依赖项

cd backend
cargo install warp

创建项目

cargo new rust-todo-api

添加依赖项

Cargo.toml文件中添加以下依赖项:

[dependencies]
warp = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

创建模型

src/models.rs文件中创建模型:

#[derive(Serialize, Deserialize)]
pub struct Todo {
    id: i32,
    title: String,
    completed: bool,
}

创建数据库

src/db.rs文件中创建数据库:

use std::collections::HashMap;

pub struct Db {
    todos: HashMap<i32, Todo>,
}

impl Db {
    pub fn new() -> Self {
        Self {
            todos: HashMap::new(),
        }
    }

    pub fn get_all_todos(&self) -> Vec<&Todo> {
        self.todos.values().collect()
    }

    pub fn get_todo(&self, id: i32) -> Option<&Todo> {
        self.todos.get(&id)
    }

    pub fn add_todo(&mut self, todo: Todo) -> i32 {
        let id = self.todos.len() as i32 + 1;
        self.todos.insert(id, todo);
        id
    }

    pub fn update_todo(&mut self, id: i32, todo: Todo) {
        self.todos.insert(id, todo);
    }

    pub fn delete_todo(&mut self, id: i32) {
        self.todos.remove(&id);
    }
}

创建路由

src/routes.rs文件中创建路由:

use warp::{Filter, reply};
use crate::models::Todo;
use crate::db::Db;

pub fn routes(db: Db) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> {
    let todos = warp::path("todos");

    todos.and(warp::get()).map(move || {
        let todos = db.get_all_todos();
        warp::reply::json(&todos)
    })
    .or(todos.and(warp::post()).and(warp::body::json()).map(move |todo: Todo| {
        let id = db.add_todo(todo);
        warp::reply::json(&id)
    }))
    .or(todos.and(warp::path::param::<i32>()).and(warp::get()).map(move |id| {
        let todo = db.get_todo(id).unwrap();
        warp::reply::json(&todo)
    }))
    .or(todos.and(warp::path::param::<i32>()).and(warp::put()).and(warp::body::json()).map(move |id, todo: Todo| {
        db.update_todo(id, todo);
        warp::reply::json(&todo)
    }))
    .or(todos.and(warp::path::param::<i32>()).and(warp::delete()).map(move |id| {
        db.delete_todo(id);
        warp::reply::json(&())
    }))
}

创建主函数

src/main.rs文件中创建主函数:

use warp::Filter;
use crate::routes;
use crate::db::Db;

#[tokio::main]
async fn main() {
    let db = Db::new();
    let routes = routes(db);

    warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}

前端

前端使用Rust编写,并使用Yew框架构建Web应用程序。

安装依赖项

cd frontend
cargo install yew

创建项目

cargo new rust-todo-app

添加依赖项

Cargo.toml文件中添加以下依赖项:

[dependencies]
yew = "0.19"

创建应用程序

src/main.rs文件中创建应用程序:

use yew::prelude::*;

struct App {
    todos: Vec<String>,
}

impl Component for App {
    type Message = ();

    fn create(_: &Context<Self>) -> Self {
        Self {
            todos: vec![],
        }
    }

    fn update(&mut self, _: &Context<Self>, _: Self::Message) -> bool {
        false
    }

    fn view(&self, ctx: &Context<Self>) -> Html {
        html! {
            <div>
                <h1>Todo List</h1>
                <ul>
                    { for self.todos.iter().map(|todo| html! { <li>{ todo }</li> }) }
                </ul>
                <button onclick={ ctx.link().callback(|_| ()) }>Add Todo</button>
            </div>
        }
    }
}

fn main() {
    yew::start_app::<App>();
}

创建组件

src/components目录中创建组件:

// todo_list.rs

use yew::prelude::*;

#[function_component(TodoList)]
pub fn todo_list(props: &Props<()>) -> Html {
    html! {
        <ul>
            { for props.todos.iter().map(|todo| html! { <li>{ todo }</li> }) }
        </ul>
    }
}

// todo_item.rs

use yew::prelude::*;

#[function_component(TodoItem)]
pub fn todo_item(props: &Props<String>) -> Html {
    html! {
        <li>{ &props.0 }</li>
    }
}

// add_todo.rs

use yew::prelude::*;

#[function_component(AddTodo)]
pub fn add_todo(props: &Props<()>) -> Html {
    html! {
        <button onclick={ props.callback(|_| ()) }>Add Todo</button>
    }
}

// filter_todos.rs

use yew::prelude::*;

#[function_component(FilterTodos)]
pub fn filter_todos(props: &Props<()>) -> Html {
    html! {
        <div>
            <label for="all">All</label>
            <input type="radio" id="all" name="filter" />
            <label