展开菜单
首页 精品内容 本月促销 装机必备 Windows macOS软件 IOS软件 Android AI PDF教程 专题
全部分类

当前位置:

首页 > 编程开发 > Rust对象中的结构体、枚举、特性详解

Rust对象中的结构体、枚举、特性详解

1 结构体 先从结构体说起。Rust 把数据组织成整体有两种方式:元组和结构体。元组灵活但没名字,结构体给每个字段起了名字,用起来更直观。结构体在代码里很常见,用来定义常用的数据结构,每个成员叫“字段”。 1.1 简介 1.1.1 定义 Rust 的结构体与元组都可以把一堆类型不同的数据捆绑成整体,

1 结构体

先从结构体说起。Rust 把数据组织成整体有两种方式:元组和结构体。元组灵活但没名字,结构体给每个字段起了名字,用起来更直观。结构体在代码里很常见,用来定义常用的数据结构,每个成员叫“字段”。

1.1 简介

1.1.1 定义

Rust 的结构体与元组都可以把一堆类型不同的数据捆绑成整体,但结构体给每个成员起了名字,访问的时候不用记下标。元组适合临时传递多个值,结构体适合长期使用的数据结构。结构体的每个成员叫作“字段”。

Rust对象中的结构体、枚举、特性详解

定义结构体时,注意结尾不需要 ;,每个字段后面用逗号分隔:

struct Site {
    domain: String,
    name: String,
    nation: String,
    found: u32
}

1.1.2 结构体实例

Rust 在语法上借鉴了不少 JavaScript 的习惯,实例化结构体用的是类似 JSON 的 key: value 语法:

let runoob = Site {
    domain: String::from("www.baidu.com"),
    name: String::from("test"),
    nation: String::from("China"),
    found: 2013
};

这种写法不仅直观,而且字段顺序可以随意。如果字段名和已有变量名相同,可以简写:

let domain = String::from("www.baidu.com");
let name = String::from("test");
let test = Site {
    domain,  // 等同于 domain : domain,
    name,    // 等同于 name : name,
    nation: String::from("China"),
    found: 2026
};

想要基于现有实例创建新实例,只改几个字段,可以用结构体更新语法:

let site = Site {
    domain: String::from("www.baidu.com"),
    name: String::from("test"),
    ..test 
};

这里有个小细节:..test 后面不能加逗号,而且至少得重新设定一个字段的值,不能完全复制。

1.1.3 元组结构体

如果觉得给每个字段起名字太麻烦,元组结构体是个不错的选择——它没有字段名,只有类型,形式上像元组。适合处理那些需要定义类型但又不想太复杂的简单数据。访问方式也和元组一样,通过 . 加下标:

fn main() {
    struct Color(u8, f64, u8);
    let black = Color(0, 0.0, 0);
    println!("black = ({}, {}, {})", black.0, black.1, black.2);
}

1.2 结构体所有权

1.2.1 输出结构体

调试的时候,能一眼看到整个结构体实例的内容太方便了。手动写格式化代码又烦又容易错,Rust 贴心地提供了 #[derive(Debug)] 这个宏,加上之后用 {:?} 就能直接打印:

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    println!("rect1 is {:?}", rect1);
}

之后在 println!print! 宏中就可以用 {:?} 占位符输出整个结构体。

1.2.2 结构体方法

方法(Method)和函数类似,但它是用来操作结构体实例的。Rust 不是面向对象语言,所有权机制就是证明,但它还是提供了方法。第一个参数必须是 &self,而且调用时不用传 self。注意 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's area is {}", rect1.area());	
    println!("{}", rect1.wider(&rect2));
}
运行结果:false

在 Rust 中,selfSelf 仅差一个字母大小写,但含义完全不同:

selfSelf
含义方法首参数的变量名(当前实例本身)类型本身的别名
类比类似 Java 中的 this类似 Java 中的"当前类名"
位置出现在方法的第一个参数出现在返回类型、字段类型等位置
本质一个绑定到实例的变量一个类型

Self 只能在 impl 块或 trait 定义内部使用。在普通函数顶层,得写具体类型名。

1.2.3 结构体关联函数

没有 &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);
}
运行结果:
Rectangle { width: 30, height: 50 }

结构体的 impl 块可以写多次,效果相当于它们内容的拼接。

1.2.4 单元结构体

单元结构体(Unit Struct)没有任何字段,它只是一个“类型标记”,实例本身不占实际数据空间(编译后大小为 0)。常用于:只需要一个类型,但不需要存储任何数据的场景。

struct UnitStruct;
fn main() {
    let u = UnitStruct;  // 创建实例,什么数据都没有
}

和其他结构体的对比:

struct UnitStruct;                    // 无字段
struct TupleStruct(i32, i32);         // 有字段,无字段名
struct NormalStruct { x: i32 }		  // 有字段,有字段名

三者的区别就在于有没有数据、数据有没有名字。单元结构体是最简单的一种——纯粹作为一个类型存在,用来实现某个 trait 或者做类型标记,而不携带任何数据。

2 枚举类

2.1 简介

Rust 的枚举比很多语言的 enum 强大得多——每个变体都能带数据,而且可以带不同类型的数据,甚至三种形式混着用:无数据、元组式数据、结构体式数据。

enum Message {
    Quit,                // 无数据(类似单元结构体)
    Move { x: i32, y: i32 },     // 结构体式:字段有名字
    Write(String),               // 元组式:只有类型,按位置
    ChangeColor(i32, i32, i32),  // 元组式,多个值
}

简单使用示例:

fn main() {
   let msgs = vec![
       Message::Quit,
       Message::Move { x: 10, y: 20 },
       Message::Write(String::from("hello")),
       Message::ChangeColor(255, 0, 0),
   ];
   for msg in msgs {
       match msg {
           Message::Quit => {
               println!("退出");
           }
           Message::Move { x, y } => {
               println!("移动到 ({}, {})", x, y);  // 按字段名解构
           }
           Message::Write(text) => {
               println!("写入: {}", text);// 按位置解构
           }
           Message::ChangeColor(r, g, b) => {
               println!("颜色: ({}, {}, {})", r, g, b);
           }
       }
   }
}

枚举变体也能有方法:

impl Message {
    fn call(&self) {
        match self {
            Message::Write(text) => println!("{}", text),
            _ => println!("其他消息"),
        }
    }
}
let m = Message::Write(String::from("hi"));
m.call();  // hi

2.2 match 语法

2.2.1 简介

Rust 通过 match 语句实现分支结构。先看看如何用 match 处理枚举:

fn main() {
    enum Book {
        Papery {index: u32},
        Electronic {url: String},
    }  
    let book = Book::Papery{index: 1001};
    let ebook = Book::Electronic{url: String::from("url...")};   
    match book {
        Book::Papery { index } => {
            println!("Papery book {}", index);
        },
        Book::Electronic { url } => {
            println!("E-book {}", url);
        }
    }
}

match 块也可以当作表达式使用,有返回值,但所有分支返回值的类型必须一样:

match 枚举类实例 {
    分类1 => 返回值表达式,
    分类2 => 返回值表达式,
    ...
}

对于枚举变体中元组数据,在 match 块中需要临时指定一个名字;对于结构体变体,可以通过 字段名:变量名 重命名:

enum Book {
    Papery(u32),
    Electronic {url: String},
}
let book = Book::Papery(1001);
match book {
    Book::Papery(i) => { //临时名字
        println!("{}", i);
    },
    Book::Electronic { url } => { //使用原来名字
        println!("{}", url);
    }
    // 或者显式重命名:字段名:变量名
    Book::Electronic { url: link } => {
        println!("{}", link);  // 变量名是 link
    },
    // 甚至可以忽略值
    Book::Electronic { url: _ } => {
        println!("has url but ignored");
    },
}

对非枚举类型进行分支选择时,必须处理例外情况,用下划线 _ 表示:

fn main() {
    let t = "abc";
    match t {
        "abc" => println!("Yes"),
        _ => {},
    }
}

2.2.2 ref 关键字

ref 用在 match 模式里,按引用绑定,防止所有权被 move 走:

let opt = Some(String::from("hello"));
match opt {
    Some(ref s) => println!("{}", s),  // ref:s 是 &String,内容的所有权不动
    None => {}
}
println!("{:?}", opt);  //  opt 还能用——如果没写 ref,String 早被 move 进分支了

为什么需要 ref?因为 match 默认按值匹配,会把字段 move 进绑定变量;加 ref 改成“绑定一个指向字段的引用”,原值所有权保留。对应的还有 ref mut(绑定 &mut)。

不过现代 Rust 里 ref 基本绝迹了,因为 2018 版引入了 match ergonomics(匹配人体工学):当 match 一个引用时,绑定模式会自动降级成引用,不用手写 ref

let opt = Some(String::from("hello"));
match &opt {           // match 的是引用
    Some(s) => println!("{}", s),  // s 自动就是 &String,不用 ref
    None => {}
}
println!("{:?}", opt); // ✅ 一样不 move

2.3 if let 语法

if let 语法格式:

if let 模式(枚举变体) = 源变量 {
    语句块
}

注意:这里是一个等号,不是两个等号,因为做的是模式绑定,不是相等比较。if let 本质上是 let 的延伸,尝试做解构绑定(把复合值拆开,把里面的各个部分分别绑定到新变量上)。

使用示例:

let i = 0;
match i {
    0 => println!("zero"),
    _ => {},
}
放入主函数运行结果:zero
// 现在用 if let 语法缩短这段代码:
let i = 0;
if let 0 = i {
    println!("zero");
}

可以在后面加一个 else 块处理例外情况。if let 可以看作是只区分两种情况的 match 的语法糖。

对于枚举类依然适用:

fn main() {
    enum Book {
        Papery(u32),
        Electronic(String)
    }
    let book = Book::Electronic(String::from("url"));
    if let Book::Papery(index) = book {
        println!("Papery {}", index);
    } else {
        println!("Not papery book");
    }
}

2.4 Option 枚举类

Option 是 Rust 标准库中的枚举类,用于填补 Rust 不支持 null 引用的空白。Rust 在语言层面彻底不允许空值,但无奈 null 能高效解决少量问题,所以引入了 Option

enum Option {
    Some(T),
    None,
}

如果要定义一个可以为空值的变量,可以这样:let opt = Option::Some("Hello");。如果想针对 opt 执行操作,必须先判断它是否是 None

fn main() {
    let opt = Option::Some("Hello");
    match opt {
        Option::Some(something) => {
            println!("{}", something);
        },
        Option::None => {
            println!("opt is nothing");
        }
    }
}

初始值为空的 Option 必须明确类型:

fn main() {
    let opt: Option<&str> = Option::None;
    match opt {
        Option::Some(something) => {
            println!("{}", something);
        },
        Option::None => {
            println!("opt is nothing");
        }
    }
}
运行结果:opt is nothing

这种设计让空值编程变得不容易,但正是构建稳定高效系统所需要的。由于 Option 是编译器默认引入的,使用时可以省略 Option::,直接写 NoneSome()Option 是一种特殊的枚举类,可以含值分支选择:

fn main() {
        let t = Some(64);
        match t {
                Some(64) => println!("Yes"),
                _ => println!("No"),
        }
}

3 特性

3.1 简介

特性(trait)有点像 Java 的接口,但更灵活。它们都是一种行为规范,可以标识哪些类有哪些方法。特性在 Rust 中用 trait 表示:

trait Descriptive {
    fn describe(&self) -> String;
}

用特性实现一个结构体,格式是 impl <特性名> for <所实现的类型名>

struct Person {
    name: String,
    age: u8
}
impl Descriptive for Person {
    fn describe(&self) -> String {
        format!("{} {}", self.name, self.age)
    }
}

Rust 同一个类可以实现多个特性,每个 impl 块只能实现一个。

3.2 默认特性

这是特性与接口的不同点:接口只能规范方法,不能定义方法;但特性可以定义方法作为默认方法。因为是“默认”,所以对象既可以重新定义,也可以不重新定义直接使用默认方法:

trait Descriptive {
    fn describe(&self) -> String {
        String::from("[Object]")
    }
}
struct Person {
    name: String,
    age: u8
}
impl Descriptive for Person {
    fn describe(&self) -> String {
        format!("{} {}", self.name, self.age)
    }
}
fn main() {
    let cali = Person {
        name: String::from("Cali"),
        age: 24
    };
    println!("{}", cali.describe());
}
运行结果:Cali 24

3.3 特性做参数

3.3.1 作为入参

很多情况下需要传递一个函数做参数,比如回调函数、设置按钮事件等。在 Rust 中可以通过传递特性参数来实现:

fn output(object: impl Descriptive) {
    println!("{}", object.describe());
}

任何实现了 Descriptive 特性的对象都可以作为这个函数的参数,函数不需要了解传入对象有没有其他属性或方法,只需要知道它一定有 Descriptive 特性规范的方法。当然,此函数内也无法使用其他属性与方法。

特性参数还有等效语法:

fn output(object: T) {
    println!("{}", object.describe());
}

如果有多个参数类型均是同一特性:

fn output_two(arg1: T, arg2: T) {
    println!("{}", arg1.describe());
    println!("{}", arg2.describe());
}

特性作类型表示时如果涉及多个特性,可以用 + 符号:

fn notify(item: impl Summary + Display)
fn notify(item: T)

注意:仅用于表示类型的时候,并不意味着可以在 impl 块中使用。

复杂的实现关系可以使用 where 关键字简化,例如:

fn some_function(t: T, u: U)
可以简化成:

fn some_function(t: T, u: U) -> i32 where 
	T: Display + Clone,
	U: Clone + Debug

3.3.2 作为出参

特性做返回值格式如下:

fn person() -> impl Descriptive {
    Person {
        name: String::from("Cali"),
        age: 24
    }
}

但有一点:特性做返回值只接受实现了该特性的对象做返回值,且在同一个函数中所有可能的返回值类型必须完全一样。比如结构体 A 与结构体 B 都实现了特性 Trait,下面这个函数是错误的:

fn some_function(bool bl) -> impl Descriptive {
    if bl {
        return A {};
    } else {
        return B {};
    }
}

3.4 dyn 关键字

3.4.1 简介

dyn 全称 dynamic dispatch(动态分发),dyn Trait 相当于 Java 里的“接口类型引用”——运行期多态。先看 Rust 的两种多态,dyn 是其中一种:

泛型 dyn Trait
类比 Java更像 C++ 模板(Java 没有对应物)就是 Java 的接口引用
分发时机编译期运行期(vtable 查找)
类型编译期已知,单态化擦除成统一的 trait 对象
性能零成本,可内联一次间接跳转
异构集合❌ Vec 里只能放一种 TVec> 混放圆和方
方法可否泛型可以❌(object safety 限制)
// ① 静态分发(泛型):编译期为每个具体类型生成专门代码
fn draw_static(shape: T) { ... }
// 编译后相当于生成了 draw_circle、draw_square 两个函数
// ② 动态分发(dyn):类型被擦除,运行期通过 vtable 找方法
fn draw_dynamic(shape: &dyn Draw) { ... }
// 只有一个函数,运行时才查"这个对象到底是哪个类型"

为什么 dyn 必须装在指针里?因为不同实现类型大小不一样(Circle 4 字节,Square 8 字节),擦除类型后编译器不知道它占多少空间——dyn Trait 是个不定长类型(unsized),不能直接放栈上。其中 & 就是引用,Rust 的引用本质上就是指针,带编译期安全检查的那种。

所以永远要包一层指针:

Box      // 堆上,独占
&dyn Draw           // 借用 = 指针 
Arc     // 共享,跨线程

3.4.2 胖指针和vtable

普通引用是 8 字节(64 位机器),但 &dyn Draw 里类型被擦除了,运行期得知道去哪个类型的方法表查,所以多带一个 vtable 地址,变成 16 字节——这就是“胖”的由来:

let d: &dyn Draw = &c;
// d 占 16 字节:[ 0x1000 | 0x7FF6AB00 ]
//                  │         └──→ vtable(Circle 实现 Draw 的方法表)
//                  └────────────→ Circle 的数据本体

vtable 是编译器为某个具体类型 × 某个 trait 的组合生成的静态表,内容如下:

vtable(Circle as Draw):
┌─────────────────────────────────┐
│ drop_in_place::         │ ← 析构函数指针(Box 丢弃时要调真正的析构)
│ size_of::   = 4         │ ← 大小(Box 释放堆内存需要知道布局)
│ align_of::  = 4         │ ← 对齐(同上)
│ ::draw          │ ← 方法的函数指针
└─────────────────────────────────┘

3.4.3 实例分析

trait Draw {
    fn draw(&self);
}
struct Circle {
    r: i32,
}
impl Draw for Circle {
    fn draw(&self) {
        println!("画一个半径 {} 的圆", self.r);
    }
}
struct Square {
    side: i32,
}
impl Draw for Square {
    fn draw(&self) {
        println!("画一个边长 {} 的正方形", self.side);
    }
}
// 瘦指针参数:只认 Circle,静态分发
fn draw_thin(shape: &Circle) {
    shape.draw();
}
// 胖指针参数:任何实现了 Draw 的类型都行,动态分发
fn draw_fat(shape: &dyn Draw) {
    shape.draw();
}
#[test]
fn test_thin_vs_fat() {
    let c = Circle { r: 5 };
    let s = Square { side: 3 };
    // ① 瘦指针:8 字节 = 只有数据地址
    let thin: &Circle = &c;
    assert_eq!(std::mem::size_of::<&Circle>(), 8);
    draw_thin(thin); // 编译期就定死调 ::draw
    // ② 胖指针:16 字节 = 数据地址 + vtable 地址
    let fat: &dyn Draw = &c; // &Circle 自动"增肥"成 &dyn Draw
    assert_eq!(std::mem::size_of::<&dyn Draw>(), 16);
    draw_fat(fat); // 运行期查 vtable 找 draw
    // ③ 胖指针的看家本领:异构集合
    let shapes: Vec<&dyn Draw> = vec![&c, &s]; // 圆和方混装进一个 Vec
    for shape in shapes {
        shape.draw(); // 每个元素运行期各查各的 vtable
    }
}

let fat: &dyn Draw = &c; 这行发生了什么?编译器执行了一次“增肥”(unsized coercion):把 &Circle 的瘦指针,拼上 Circle as Drawvtable 地址,组装成 16 字节的胖指针。&s&dyn Draw 时拼的则是 Squarevtable——同一个 &dyn Draw 类型,里面装的表不一样,运行时行为自然不同。

第 ③ 处的 Vecdyn 存在的核心理由:由于 Vec 要求元素类型统一,瘦指针 &Circle&Square 是两个不同类型,混装不了;但擦除成 &dyn Draw 后统一成同一个类型了,随便混。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
精品专题 更多
本月促销

正软商城本月促销专区,汇集办公、设计、安全、影音、系统工具及AI软件等正版软件优惠活动,提供限时折扣、特价授权和优惠购买信息,活动库存及价格以页面实时展示为准。

装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
灵活计算器
灵活计算器

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

图几
图几

图几是一款适用于 macOS 的截图、标注与美化工具,支持离线操作保障隐私。界面整理和高频系统操作被放到一起考虑,桌面或窗口内容一多时,管理起来会更省心。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Menuist
Menuist

Menuist 是一款面向 macOS 的 Finder 右键菜单增强工具,主要用来补充新建文件、快捷导航等常用操作,让日常文件管理和访问路径时更高效、更顺手。

Mole
Mole

Mole 是一款专为 Mac 设计的深度清理优化工具,涵盖缓存清理、应用管理及实时状态监控等功能。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

WINDOWS 更多
Windows 10
Windows 10

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

傲梅轻松备份
傲梅轻松备份

傲梅轻松备份是一款专业易用的数据备份软件,为重要数据提供安全保障。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Wise Folder Hider Pro
Wise Folder Hider Pro

Wise Folder Hider Pro 是一款专业级文件和文件夹隐藏加密软件,为私密数据添加多重保护。高频操作更强调就近处理,浏览、整理和跨目录移动文件时,来回切换和重复点击都会少很多。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

PinStack
PinStack

PinStack是一款轻量级的Windows平台剪贴板管理工具,优化您的剪贴板使用体验。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Seer
Seer

Seer是一款在Win平台下的空格键功能增强效率工具,只需轻敲空格键,就能预览几乎任何格式的文件。它更适合把零散的小功能集中起来使用,处理高频琐碎任务时会更省事。