您现在的位置是:网站首页> PY&Rust
Rust学习资料
- PY&Rust
- 2024-09-30
- 602人已阅读
Rust学习资料
Rust下载安装
1. 安装Rust环境
***可在在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"、回车
随后出现以下选项
如已经安装了vs2022直接选1就可以不用2手动安装
依次输入"2"、回车、"x86_64-pc-windows-gnu"、回车、"nightly"、回车、"y"、回车,随后选项更新为
随后输入"1"、回车即可开始安装最新版,等待一定时间后提示如下即表示Rust已经正常安装。
截至目前,你已安装了工具链管理工具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,选择使用即可
所有选项均可在用户设置中找到。
截至目前,理论上开发环境已经完成,且为模拟新手第一次安装的情况,我先卸载了rust并清除了相关配置后重新安装、配置了一遍,但由于可能因遗漏而未清除的配置,我的起步环境可能与你的不同,欢迎指正。
在终端中输入命令:
cargo new greeting
当前文件下下会构建一个名叫 greeting 的 Rust 工程目录
调试需要安装插件Native Debug和C/C++扩展
调试文件launch.json
重要目录
c:\Users\[用户名]\.cargo
c:\Users\[用户名]\.rustup
调试过程中,当要跟踪到rust内部代码时,会跳出如下提示框,这时需要建一个C:\rustc\b8cedc00407a4c56a3bda1ed605c6fc166655447的目录,并将用户目录下的.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src拷到前面的目录下。这样就能跟踪到内部代码了。
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文件夹下。
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、运行结果如下图。
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 库可供选择。以下是一些使用较为广泛的 UI 库:
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 库取决于你的具体需求、目标平台以及个人偏好。建议你研究和对比几个库,选择最适合你项目的那个。
一个使用 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 的文档和示例来进一步了解它的功能和用法。
上一篇:如何用Python开发你的网站
下一篇:Python硬件相关开发