您现在的位置是:网站首页> PY&Rust

Rust学习资料

  • PY&Rust
  • 2025-09-07
  • 1226人已阅读
摘要

Rust学习资料


1.jpg


Rust下载安装

Cargo创建项目编译项目等使用说明

在线Rust学习文本资料

Rust的包、模块、结构体和特征(接口)的概念

Rust学习笔记

  Rust中的关键字

  结构体方法

  结构体关联函数

  Rust 中的mod 使用

最新最全Rust编程语言入门教程

Rust编程语言入门教程

2022年末 Rust权威编程语言入门教程

Rust UI库



Rust下载安装

1. 安装Rust环境

点击进入Rust下载页面

在线体验rust编程

点击查看原文

点击查看windows下rust文档

rust默认安装路径

1.Windows 系统

使用 rustup 安装时,默认路径通常为:

C:\Users\<用户名>\.cargo\

其中包含:

bin\:存放 rustc、cargo 等可执行文件

registry\: crate 注册表缓存

toolchains\:不同版本的 Rust 工具链

2.Linux 或 macOS 系统

默认安装路径为用户主目录下的隐藏文件夹:

~/.cargo/(即 /home/<用户名>/.cargo/ 或 /Users/<用户名>/.cargo/)

结构与 Windows 类似,bin 目录包含可执行文件。


***可在在windows的环境变量里面设置RUSTUP_HOME 以及 CARGO_HOME 通过设置这两个环境变量来设置默认安装路径。

环境变量:

变量名 值

CARGO_HOME  cargo 的安装路径(必须为绝对路径),例如D:\Rust\Cargo

RUSTUP_HOME rustup 的安装路径(必须为绝对路径),例如 D:\Rust\Rustup

RUSTUP_DIST_SERVER  https://mirrors.ustc.edu.cn/rust-static

RUSTUP_UPDATE_ROOT https://mirrors.ustc.edu.cn/rust-static/rustup

RUST_BACKTRACE full

RUST  某toolchain的目录,如%RUSTUP_HOME%\toolchains\stable-x86_64-pc-windows-gnu。

RUST_SRC_PATH  rust的源码目录,如%RUST%\lib\rustlib\src\rust\src,若你的rustlib中没有src,请执行> rustup component add rust-src。

RUSTBINPATH  %CARGO_PATH%\bin。


卸载 Rust

在任何时候如果您想卸载 Rust,您可以运行 rustup self uninstall。但我们会想念您的!

打开rustup-init.exe文件,若出现以下提示,按"Y"、回车

1.png

随后出现以下选项

1.png

如已经安装了vs2022直接选1就可以不用2手动安装

依次输入"2"、回车、"x86_64-pc-windows-gnu"、回车、"nightly"、回车、"y"、回车,随后选项更新为

2.png


随后输入"1"、回车即可开始安装最新版,等待一定时间后提示如下即表示Rust已经正常安装。

3.png


截至目前,你已安装了工具链管理工具rustup、项目构建工具cargo、Rust编译环境、Rust标准库文档

2. 配置开发工具

rustup component add rust-src rustc-dev llvm-tools-preview

1. 执行命令"cargo install racer"

2. 执行命令"cargo install rustfmt"

3. 执行命令"rustup component add rls"

4. 执行命令"rustup component add rust-analysis"

5. 执行命令"rustup component add rust-src"

6. 设置名为"RUST_SRC_HOME"的环境变量为"C:\Users\[home_dir_name]\.multirust\toolchains\nightly-x86_64-pc-windows-gnu\lib\rustlib\src\rust\src"

其中"home_dir_name"为你的家目录的目录名

7. 安装VScode编辑器

8. 安装名为rust-analyzer 的插件并重新加载后用VScode打开任意扩展名为rs的文件

9. 跟随插件引导完成配置,共有四项需要配置,其中两项用于选择rustup的工具链,由于之前的内容中只安装了nightly版本的工具链,故均只可选择nightly;另外两项一个是选择补全所用工具,选择rls即可,随后要求选择是否使用Rustfmt,选择使用即可

所有选项均可在用户设置中找到。

1.png

截至目前,理论上开发环境已经完成,且为模拟新手第一次安装的情况,我先卸载了rust并清除了相关配置后重新安装、配置了一遍,但由于可能因遗漏而未清除的配置,我的起步环境可能与你的不同,欢迎指正。

在终端中输入命令

cargo new greeting 

当前文件下下会构建一个名叫 greeting 的 Rust 工程目录


调试需要安装插件Native Debug和C/C++扩展

调试文件launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(Windows)启动",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/target/debug/greeting.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false    
        },
        {
            "name": "(gdb)启动",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/target/debug/${workspaceFolderBasename}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "这里填GDB所在的目录",
            "setupCommands": [
                {
                    "description": "为gdb启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true    
                }
            ]
        }
    ]
}

重要目录

c:\Users\[用户名]\.cargo

c:\Users\[用户名]\.rustup

调试过程中,当要跟踪到rust内部代码时,会跳出如下提示框,这时需要建一个C:\rustc\b8cedc00407a4c56a3bda1ed605c6fc166655447的目录,并将用户目录下的.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src拷到前面的目录下。这样就能跟踪到内部代码了。

1.png



Cargo创建项目编译项目等使用说明

在 Rust 中,可以使用 Cargo 工具来编译生成可执行文件。Cargo 是 Rust 的构建系统和包管理器,它简化了 Rust 项目的构建、测试和部署过程。

要使用 Cargo 编译生成可执行文件,可以按照以下步骤进行:


确保已经安装了 Rust 和 Cargo。可以从 Rust 官方网站(https://www.rust-lang.org/)下载并安装。

打开终端或命令行界面,导航到你的 Rust 项目目录。


如果你还没有创建 Rust 项目,可以使用以下命令创建一个新的二进制项目:

cargo new my_project

这将创建一个名为 "my_project" 的新目录,其中包含 Cargo.toml 配置文件和 src 目录。

进入项目目录:

cd my_project

编写你的 Rust 代码,并将其保存在 src 目录下的 main.rs 文件中。

使用以下命令编译项目:

cargo build --release

这将在项目目录下的 target/release 目录中生成优化后的可执行文件。


运行生成的可执行文件:

在 Linux/macOS 上:

./target/release/my_project


在 Windows 上:

.\target\release\my_project.exe

注意:将 "my_project" 替换为你实际的项目名称。

Cargo 还提供了其他有用的命令:

cargo run:编译并运行项目,适合开发和测试阶段。

cargo test:运行项目的单元测试。

cargo doc:生成项目的文档。

cargo clean:清理项目的构建结果。

使用 Cargo 可以大大简化 Rust 项目的管理和构建过程。它会自动处理依赖项的下载和编译,并提供了一致的项目结构和构建命令。



Rust的包、模块、结构体和特征(接口)的概念

包(Crate)和模块(Module)的区别:

包(Crate):

包是Rust中最高级别的代码组织单位。

一个包可以包含多个模块

包可以是二进制包(可执行程序)或库包(供其他程序使用的代码库)。

每个包都有一个Cargo.toml文件,用于描述包的元数据和依赖关系。


模块(Module):

模块是在包内组织代码的方式。

模块可以包含函数、结构体、特征、常量等。

模块可以嵌套,形成层次结构

模块用于控制项的可见性(公有或私有)。


示例:

// 这是一个名为 "my_package" 的包


// lib.rs (库包的根模块)

mod front_of_house {

    pub mod hosting {

        pub fn add_to_waitlist() {}

    }

}


pub fn eat_at_restaurant() {

    front_of_house::hosting::add_to_waitlist();

}


// 在同一个包中的另一个文件 (比如 src/back_of_house.rs)

pub struct Breakfast {

    pub toast: String,

    seasonal_fruit: String,

}


impl Breakfast {

    pub fn summer(toast: &str) -> Breakfast {

        Breakfast {

            toast: String::from(toast),

            seasonal_fruit: String::from("peaches"),

        }

    }

}


结构体(Struct)和特征(Trait):

结构体(Struct):

结构体是自定义数据类型,用于组合多个相关的值。

可以包含多个命名字段。

可以实现方法。


特征(Trait):

特征定义了一组方法签名,可以被其他类型实现。

类似于其他语言中的接口概念。

允许抽象和多态。

示例:


// 定义一个结构体

struct Rectangle {

    width: u32,

    height: u32,

}


// 为结构体实现方法

impl Rectangle {

    fn area(&self) -> u32 {

        self.width * self.height

    }

}


// 定义一个特征

trait Drawable {

    fn draw(&self);

}


// 为Rectangle实现Drawable特征

impl Drawable for Rectangle {

    fn draw(&self) {

        println!("Drawing a rectangle of {}x{}", self.width, self.height);

    }

}


// 另一个实现Drawable特征的结构体

struct Circle {

    radius: f64,

}


impl Drawable for Circle {

    fn draw(&self) {

        println!("Drawing a circle with radius {}", self.radius);

    }

}


// 使用特征作为参数

fn draw_shape(shape: &impl Drawable) {

    shape.draw();

}


fn main() {

    let rect = Rectangle { width: 30, height: 50 };

    let circ = Circle { radius: 10.0 };


    draw_shape(&rect);

    draw_shape(&circ);

    

// 调用 area 方法

    let area1 = rect .area(); 

    println!("The area of the rectangle is {} square pixels.", area1);


}

在这个例子中:

Rectangle和Circle是结构体。

Drawable是一个特征,定义了draw方法。

两个结构体都实现了Drawable特征。

draw_shape函数可以接受任何实现了Drawable特征的类型。

Rust没有传统意义上的类,但结构体和特征的组合提供了类似的功能:


结构体用于数据封装

impl块用于定义方法

特征用于定义接口和实现多态

这种设计提供了更大的灵活性和更清晰的代码组织







Rust学习笔记

Rust中的关键字

严格关键字

as - 强制类型转换,消除特定包含项的 trait 的歧义,或者对 use 和 extern crate 语句中的项重命名

async - 返回一个 Future 而不是阻塞当前线程( 2018版新增)

await - 暂停执行直到 Future 的结果就绪( 2018版新增)

break - 立刻退出循环

const - 定义常量或不变裸指针(constant raw pointer)

continue - 继续进入下一次循环迭代

crate - 链接(link)一个外部 crate 或一个代表宏定义的 crate 的宏变量

dyn - 动态分发 trait 对象

else - 作为 if 和 if let 控制流结构的 fallback

enum - 定义一个枚举

extern - 链接一个外部 crate 、函数或变量

false - 布尔字面值 false

fn - 定义一个函数或 函数指针类型 (function pointer type)

for - 遍历一个迭代器或实现一个 trait 或者指定一个更高级的生命周期

if - 基于条件表达式的结果分支

impl - 实现自有或 trait 功能

in - for - 循环语法的一部分

let - 绑定一个变量

loop - 无条件循环

match - 模式匹配

mod - 定义一个模块

move - 使闭包获取其所捕获项的所有权

mut - 表示引用、裸指针或模式绑定的可变性

pub - 表示结构体字段、impl 块或模块的公有可见性

ref - 通过引用绑定

return - 从函数中返回

Self - 定义或实现 trait 的类型的类型别名

self - 表示方法本身或当前模块

static - 表示全局变量或在整个程序执行期间保持其生命周期

struct - 定义一个结构体

super - 表示当前模块的父模块

trait - 定义一个 trait

true - 布尔字面值 true

type - 定义一个类型别名或关联类型

union - 定义一个 union 并且是 union 声明中唯一用到的关键字

use - 引入外部空间的符号

where - 表示一个约束类型的从句

while - 基于一个表达式的结果判断是否进行循环



保留关键字

以下关键字目前没有任何功能,不过由 Rust 保留以备将来使用

abstract

become

box

do

final

macro

override

priv

try

typeof

unsized

virtual

yield



弱关键字

unsafe - 表示不安全的代码、函数、trait 或实现

static




函数中途返回使用return

fn check_number(x: i32) -> bool {

    if x == 0 {

        return true;

    }

    false

}


fn main() {

    let result = check_number(0);

    println!("result: {}", result); // 输出:result: true

}




数据类型

整数型(Integer)

整数型简称整型,按照比特位长度和有无符号分为以下种类:

位长度 有符号 无符号

8-bit i8 u8

16-bit i16 u16

32-bit i32 u32

64-bit i64 u64

128-bit i128 u128

arch isize usize

isize 和 usize 两种整数类型是用来衡量数据大小的,它们的位长度取决于所运行的目标平台,如果是 32 位架构的处理器将使用 32 位位长度整型。



浮点数型(Floating-Point)

Rust 与其它语言一样支持 32 位浮点数(f32)和 64 位浮点数(f64)。默认情况下,64.0 将表示 64 位浮点数,因为现代计算机处理器对两种浮点数计算的速度几乎相同,但 64 位浮点数精度更高。

实例

fn main() {

    let x = 2.0; // f64

    let y: f32 = 3.0; // f32

}



布尔型

布尔型用 bool 表示,值只能为 true 或 false。


字符型

字符型用 char 表示。

Rust的 char 类型大小为 4 个字节



复合类型

元组是用一对 ( ) 包括的一组数据,可以包含不同种类的数据:


实例

let tup: (i32, f64, u8) = (500, 6.4, 1);

// tup.0 等于 500

// tup.1 等于 6.4

// tup.2 等于 1

let (x, y, z) = tup;

// y 等于 6.4

数组用一对 [ ] 包括的同类型数据。


实例

let a = [1, 2, 3, 4, 5];

// a 是一个长度为 5 的整型数组


let b = ["January", "February", "March"];

// b 是一个长度为 3 的字符串数组


let c: [i32; 5] = [1, 2, 3, 4, 5];

// c 是一个长度为 5 的 i32 数组


let d = [3; 5];

// 等同于 let d = [3, 3, 3, 3, 3];


let first = a[0];

let second = a[1];

// 数组访问


a[0] = 123; // 错误:数组 a 不可变

let mut a = [1, 2, 3];

a[0] = 4; // 正确



闭包的声明

闭包的语法声明:

|参数...| { 表达式 }


闭包的参数和返回值: 闭包可以有零个或多个参数,并且可以返回一个值。

let calculate = |a, b, c| a * b + c;


闭包的调用:闭包可以像函数一样被调用。

let result = calculate(1, 2, 3);


结构体定义

这是一个结构体定义:

struct Site {

    domain: String,

    name: String,

    nation: String,

    found: u32

}


构体实例

Rust 很多地方受 JavaScript 影响,在实例化结构体的时候用 JSON 对象的 key: value 语法来实现定义:

实例

let runoob = Site {

    domain: String::from("www.runoob.com"),

    name: String::from("RUNOOB"),

    nation: String::from("China"),

    found: 2013

};


如果你不了解 JSON 对象,你可以不用管它,记住格式就可以了:

结构体类名 {

    字段名 : 字段值,

    ...

}

这样的好处是不仅使程序更加直观,还不需要按照定义的顺序来输入成员的值。


如果正在实例化的结构体有字段名称和现存变量名称一样的,可以简化书写:

实例

let domain = String::from("www.runoob.com");

let name = String::from("RUNOOB");

let runoob = Site {

    domain,  // 等同于 domain : domain,

    name,    // 等同于 name : name,

    nation: String::from("China"),

    traffic: 2013

};


有这样一种情况:你想要新建一个结构体的实例,其中大部分属性需要被设置成与现存的一个结构体属性一样,仅需更改其中的一两个字段的值,可以使用结构体更新语法:

let site = Site {

    domain: String::from("www.runoob.com"),

    name: String::from("RUNOOB"),

    ..runoob

};

注意:..runoob 后面不可以有逗号。这种语法不允许一成不变的复制另一个结构体实例,意思就是说至少重新设定一个字段的值才能引用其他实例的值。



元组结构体

有一种更简单的定义和使用结构体的方式:元组结构体。

元组结构体是一种形式是元组的结构体。

与元组的区别是它有名字和固定的类型格式。它存在的意义是为了处理那些需要定义类型(经常使用)又不想太复杂的简单数据:


struct Color(u8, u8, u8);

struct Point(f64, f64);


let black = Color(0, 0, 0);

let origin = Point(0.0, 0.0);


实例

fn main() {

    struct Color(u8, u8, u8);

    struct Point(f64, f64);


    let black = Color(0, 0, 0);

    let origin = Point(0.0, 0.0);


    println!("black = ({}, {}, {})", black.0, black.1, black.2);

    println!("origin = ({}, {})", origin.0, origin.1);

}


结构体方法

方法(Method)和函数(Function)类似,只不过它是用来操作结构体实例的。

实例

struct Rectangle {

    width: u32,

    height: u32,

}

   

impl Rectangle {

    fn area(&self) -> u32 {

        self.width * self.height

    }

}


fn main() {

    let rect1 = Rectangle { width: 30, height: 50 };

    println!("rect1's area is {}", rect1.area());

}


请注意,在调用结构体方法的时候不需要填写 self ,这是出于对使用方便性的考虑。

一个多参数的例子:

实例

struct Rectangle {

    width: u32,

    height: u32,

}


impl Rectangle {

    fn area(&self) -> u32 {

        self.width * self.height

    }


    fn wider(&self, rect: &Rectangle) -> bool {

        self.width > rect.width

    }

}


fn main() {

    let rect1 = Rectangle { width: 30, height: 50 };

    let rect2 = Rectangle { width: 40, height: 20 };


    println!("{}", rect1.wider(&rect2));

}



结构体关联函数

之所以"结构体方法"不叫"结构体函数"是因为"函数"这个名字留给了这种函数:它在 impl 块中却没有 &self 参数。

这种函数不依赖实例,但是使用它需要声明是在哪个 impl 块中的。

一直使用的 String::from 函数就是一个"关联函数"。


实例

#[derive(Debug)]

struct Rectangle {

    width: u32,

    height: u32,

}


impl Rectangle {

    fn create(width: u32, height: u32) -> Rectangle {

        Rectangle { width, height }

    }

}


fn main() {

    let rect = Rectangle::create(30, 50);

    println!("{:?}", rect);

}


Rust 中的mod 使用

项目目录如下图。

2.1、mod.rs中是需要引入的模块代码。

2.2、main.rs和文件夹utils在src文件夹下。

1.png


2.3、mod.rs代码如下。

pub mod nation{

    pub mod government{

        pub fn govern()

        {

            let a=String::from("govern");

            println!("This is {}",a);

        }

    }

 

    mod congress{

        pub fn legislate() 

        {

            let a=String::from("legislate");

            println!("This is {}",a);

        }

    }

 

 

    pub mod court{

        pub fn judicial()

        {

            super::congress::legislate();

        }

    }

}

3、main.rs代码如下。

mod utils; 

fn main() {

    utils::nation::government::govern();

    utils::nation::court::judicial();

}

4、缩短模块引用路径方法如下。

mod utils;

use utils::nation::court::judicial;

use utils::nation::government::govern;

 

fn main() {

    govern();

    judicial()

}

5、运行结果如下图。

1.png


Rust 枚举类

枚举类在 Rust 中并不像其他编程语言中的概念那样简单,但依然可以十分简单的使用:

实例

#[derive(Debug)]


enum Book {

    Papery, Electronic

}


fn main() {

    let book = Book::Papery;

    println!("{:?}", book);

}


如果你现在正在开发一个图书管理系统,你需要描述两种书的不同属性(纸质书有索书号,电子书只有 URL),你可以为枚举类成员添加元组属性描述:


enum Book {

    Papery(u32),

    Electronic(String),

}


let book = Book::Papery(1001);

let ebook = Book::Electronic(String::from("url://..."));


如果你想为属性命名,可以用结构体语法:

enum Book {

    Papery { index: u32 },

    Electronic { url: String },

}

let book = Book::Papery{index: 1001};


Rust 中有三个重要的组织概念:箱、包、模块

箱(Crate)

"箱"是二进制程序文件或者库文件,存在于"包"中。

"箱"是树状结构的,它的树根是编译器开始运行时编译的源文件所编译的程序。

注意:"二进制程序文件"不一定是"二进制可执行文件",只能确定是是包含目标机器语言的文件,文件格式随编译环境的不同而不同。


包(Package)

当我们使用 Cargo 执行 new 命令创建 Rust 工程时,工程目录下会建立一个 Cargo.toml 文件。工程的实质就是一个包,包必须由一个 Cargo.toml 文件来管理,该文件描述了包的基本信息以及依赖项。

一个包最多包含一个库"箱",可以包含任意数量的二进制"箱",但是至少包含一个"箱"(不管是库还是二进制"箱")。

当使用 cargo new 命令创建完包之后,src 目录下会生成一个 main.rs 源文件,Cargo 默认这个文件为二进制箱的根,编译之后的二进制箱将与包名相同。


模块(Module)

对于一个软件工程来说,我们往往按照所使用的编程语言的组织规范来进行组织,组织模块的主要结构往往是树。Java 组织功能模块的主要单位是类,而 JavaScript 组织模块的主要方式是 function。

这些先进的语言的组织单位可以层层包含,就像文件系统的目录结构一样。Rust 中的组织单位是模块(Module)


mod nation {

    mod government {

        fn govern() {}

    }

    mod congress {

        fn legislate() {}

    }

    mod court {

        fn judicial() {}

    }

}


访问权限

Rust 中有两种简单的访问权:公共(public)和私有(private)。

默认情况下,如果不加修饰符,模块中的成员访问权将是私有的。

如果想使用公共权限,需要使用 pub 关键字。

对于私有的模块,只有在与其平级的位置或下级的位置才能访问,不能从其外部访问。

实例

mod nation {

    pub mod government {

        pub fn govern() {}

    }


    mod congress {

        pub fn legislate() {}

    }

   

    mod court {

        fn judicial() {

            super::congress::legislate();

        }

    }

}


fn main() {

    nation::government::govern();

}


mod back_of_house {

    pub struct Breakfast {

        pub toast: String,

        seasonal_fruit: String,

    }


    impl Breakfast {

        pub fn summer(toast: &str) -> Breakfast {

            Breakfast {

                toast: String::from(toast),

                seasonal_fruit: String::from("peaches"),

            }

        }

    }

}

pub fn eat_at_restaurant() {

    let mut meal = back_of_house::Breakfast::summer("Rye");

    meal.toast = String::from("Wheat");

    println!("I'd like {} toast please", meal.toast);

}

fn main() {

    eat_at_restaurant()

}



use 关键字

use 关键字能够将模块标识符引入当前作用域:

实例

mod nation {

    pub mod government {

        pub fn govern() {}

    }

}

use crate::nation::government::govern;


fn main() {

    govern();

}


因为 use 关键字把 govern 标识符导入到了当前的模块下,可以直接使用。

这样就解决了局部模块路径过长的问题。

当然,有些情况下存在两个相同的名称,且同样需要导入,我们可以使用 as 关键字为标识符添加别名:

实例

mod nation {

    pub mod government {

        pub fn govern() {}

    }

    pub fn govern() {}

}

   

use crate::nation::government::govern;

use crate::nation::govern as nation_govern;


fn main() {

    nation_govern();

    govern();

}


Rust 面向对象

下面建造一个完整的类:

second.rs

pub struct ClassName {

    field: i32,

}


impl ClassName {

    pub fn new(value: i32) -> ClassName {

        ClassName {

            field: value

        }

    }


    pub fn public_method(&self) {

        println!("from public method");

        self.private_method();

    }


    fn private_method(&self) {

        println!("from private method");

    }

}

main.rs

mod second;

use second::ClassName;


fn main() {

    let object = ClassName::new(1024);

    object.public_method();

}


Rust 并发编程

Rust 中通过 std::thread::spawn 函数创建新线程:

实例

use std::thread;

use std::time::Duration;


fn spawn_function() {

    for i in 0..5 {

        println!("spawned thread print {}", i);

        thread::sleep(Duration::from_millis(1));

    }

}


fn main() {

    thread::spawn(spawn_function);


    for i in 0..3 {

        println!("main thread print {}", i);

        thread::sleep(Duration::from_millis(1));

    }

}


在 Rust 中,impl 块用于为类型实现功能,而 for 关键字用于指定 impl 块所针对的具体类型

语法:

impl <Trait> for <Type> {

    // Trait 方法的实现

}

<Trait> 是要实现的 trait 的名称。

<Type> 是要为其实现 trait 的类型的名称。

作用:

for 关键字将 impl 块与特定的类型关联起来,使得该类型能够使用 trait 中定义的方法。

示例:


struct Circle {

    radius: f64,

}


trait Area {

    fn area(&self) -> f64;

}


// 为 Circle 类型实现 Area trait

impl Area for Circle {

    fn area(&self) -> f64 {

        std::f64::consts::PI * self.radius * self.radius

    }

}


fn main() {

    let circle = Circle { radius: 5.0 };

    println!("Circle area: {}", circle.area()); // 使用 Area trait 中的 area() 方法

}

在这个例子中:


我们定义了一个 Circle 结构体和一个 Area trait。

Area trait 中定义了一个 area() 方法,用于计算面积。

我们使用 impl Area for Circle 语句为 Circle 类型实现了 Area trait。

在 impl 块中,我们实现了 area() 方法,用于计算圆形的面积。

最后,在 main() 函数中,我们创建了一个 Circle 实例,并调用了 area() 方法来计算圆形的面积。

总结:


for 关键字在 impl 块中用于指定要为其实现 trait 的具体类型,从而将 trait 的功能应用于该类型。






2022年末 Rust权威编程语言入门教程

点击查看原视频



最新最全Rust编程语言入门教程

点击查看原视频



Rust编程语言入门教程

点击查看原视频



Rust UI库

rust ui框架slint tauri bevy egui

在 Rust 生态系统中,有多个流行的 UI 库可供选择。以下是一些使用较为广泛的 UI 库:

slint:用 Rust 编写的声明式开源 GUI 工具包,可用于为桌面和嵌入式设备等构建原生用户界面

egui: 一个简单、快速、可移植的即时模式 GUI 库。它使用 Rust 编写,可以轻松地创建跨平台的用户界面。

druid: 由 Rust 团队成员开发的一个现代化、跨平台的原生 GUI 库。它强调简单性、可组合性和高性能。

iced: 一个跨平台的 GUI 库,专注于简单性和类型安全。它借鉴了 Elm 的思想,提供了声明式的 API 和响应式的编程模型。

gtk-rs: Rust 绑定的 GTK 库,可以使用 Rust 编写 GTK 应用程序。GTK 是一个成熟、跨平台的 GUI 工具包。

Tauri: 一个使用 Rust 和 Web 技术构建跨平台桌面应用的框架。它允许使用 HTML、CSS 和 JavaScript 创建用户界面,同时利用 Rust 的性能和安全性。

Azul: 一个用 Rust 编写的跨平台 GUI 框架,旨在提供一致的开发体验和原生的性能。它使用即时模式渲染,支持 CSS 样式和 SVG。

这些只是 Rust 中一部分流行的 UI 库,还有其他一些库也在不断发展和完善中,如 Moxie、Relm 等。选择哪个 UI 库取决于你的具体需求、目标平台以及个人偏好。建议你研究和对比几个库,选择最适合你项目的那个。



Slint 的例子

fn main() {

    MainWindow::new().unwrap().run().unwrap();

}

slint::slint! {

    export component MainWindow inherits Window {

        Text {

            text: "hello world";

            color: green;

        }

    }

}



一个使用 egui 创建简单计数器应用的例子:

use egui::{CentralPanel, CtxRef, Labelable, Ui};


struct MyApp {

    counter: i32,

}


impl Default for MyApp {

    fn default() -> Self {

        Self { counter: 0 }

    }

}


impl MyApp {

    fn new(cc: &eframe::CreationContext<'_>) -> Self {

        Default::default()

    }

}


impl eframe::App for MyApp {

    fn update(&mut self, ctx: &egui::CtxRef, _frame: &mut eframe::Frame) {

        CentralPanel::default().show(ctx, |ui| {

            ui.heading("Counter App");

            ui.horizontal(|ui| {

                if ui.button("-").clicked() {

                    self.counter -= 1;

                }

                ui.label(self.counter.to_string());

                if ui.button("+").clicked() {

                    self.counter += 1;

                }

            });

        });

    }

}


fn main() {

    let app = MyApp::default();

    let native_options = eframe::NativeOptions::default();

    eframe::run_native(Box::new(app), native_options);

}

这个例子创建了一个简单的计数器应用:


我们定义了一个 MyApp 结构体,包含一个 counter 字段用于存储当前计数值。

实现了 Default trait,提供了 MyApp 的默认值。

实现了 eframe::App trait 的 update 方法,定义了应用的 UI 布局和交互逻辑。

在 update 方法中,我们使用 CentralPanel 创建了一个居中的面板,并在其中添加了标题、减号按钮、计数值标签和加号按钮。

当减号按钮被点击时,计数值减 1;当加号按钮被点击时,计数值加 1。

在 main 函数中,我们创建了 MyApp 的实例,并使用 eframe::run_native 启动应用。

运行这个例子,你将看到一个居中的计数器应用,可以通过点击加号和减号按钮来增减计数值。


这只是一个简单的示例,egui 还提供了许多其他的 UI 组件和布局方式,可以用来创建更复杂的用户界面。你可以参考 egui 的文档和示例来进一步了解它的功能和用法。




Tauri 的一些例子

文件操作示例

文件对话框 :打开文件对话框并获取用户选择的文件路径。

const { dialog } = require('tauri/api');


dialog.open({ directory: false, multiple: false })

  .then((result) => {

    console.log('选中的文件路径:', result);

  })

  .catch((error) => {

    console.error('打开文件对话框时出错:', error);

  });


读写文件 :使用 Tauri API 读写本地文件。

const { readTextFile, writeTextFile } = require('@tauri-apps/api/fs');


// 读取文件内容

async function readFileContent(filePath) {

    try {

      const content = await readTextFile(filePath);

      console.log('File content:', content);

    } catch (error) {

      console.error('Error reading file:', error);

    }

}


// 写入文件内容

async function writeFileContent(filePath, data) {

    try {

      await writeTextFile(filePath, data);

      console.log('File written successfully!');

    } catch (error) {

      console.error('Error writing file:', error);

    }

}


系统通知示例

使用 Tauri API 发送系统通知。

const { Notification } = require('@tauri-apps/api/notification');


// 发送通知

function sendNotification(title, message) {

    const notification = new Notification({ title, body: message });

    notification.show();

}


窗口管理示例

监听窗口关闭事件,并在关闭前执行相关操作。

import { appWindow } from '@tauri-apps/api/window'


appWindow.listen('tauri://window-close-requested', () => {

    // 窗口关闭前需要执行的任务...

    await appWindow.close()

})


前后端通信示例

前端调用 Rust :在 Rust 中定义指令,在前端通过 invoke 函数调用指令。

// Rust 中的指令

#[tauri::command]

fn greet(name: &str) -> String {

    format!("👋 Hello, {}!", name)

}


fn main() {

    tauri::Builder::default()

        .invoke_handler(tauri::generate_handler![greet]) // 注册指令

        .run(tauri::generate_context!())

        .expect("❌ error while running tauri application.")

}


// 前端调用

import { invoke } from '@tauri-apps/api'


invoke('greet', { name: '🚥 红绿灯的黄' })

    .then(response => {

        window.header.innerHTML = response

    })


事件通信 :通过事件进行前后端通信。

// 前端发送事件

import { emit, listen } from '@tauri-apps/api/event'


const greetMsg = ref("");

const name = ref("");


function greet() {

    emit("greet", { name: name.value });

}


onMounted(async () => {

    const unlisten = await listen('hello', (event) => {

        greetMsg.value = event.payload;

    });

})


// Rust 中监听事件并处理

use serde::{Deserialize, Serialize, Debug};

use tauri::Manager;


#[derive(Serialize, Deserialize, Debug)]

struct Greet {

    name: String,

}


fn main() {

    tauri::Builder::default()

        .setup(|app| {

            let callback_app_handle = app.app_handle().clone();

            let _event_id = app.listen_global("greet", move |event| {

                let greet_msg: Greet = serde_json::from_str(&event.payload().unwrap()).unwrap();

                let msg = format!("Hello, {}! You've been greeted from Rust!", greet_msg.name);

                println!("{}", msg);

                let _ = &callback_app_handle.emit_all("hello", msg);

            });

            Ok(())

        })

        .run(tauri::generate_context!())

        .expect("error while running tauri application");

}

这些示例展示了 Tauri 的一些基本功能和用法,通过这些示例,开发者可以快速上手并构建跨平台的桌面应用。

















Top