【一起学Rust | 进阶篇】使用Bon快速生成builder,提高代码质量

news2024/11/26 4:38:58

文章目录

  • 前言
  • 一、安装Bon
  • 二、使用步骤
    • 1.为方法实现builder
    • 2.实现关联方法的builder
    • 3. 为结构体实现builder
    • 4. `Option<T>`字段成为可选项
    • 5. 实现`Into`转化
  • 参考文档


前言

在 Rust 编程语言中,除了广为人知的单例模式之外,工厂模式也是极为容易见到的一种设计模式。工厂模式在 Rust 中不仅出现频率高,而且还是官方大力推荐的写法。无论是 Rust 的标准库,还是众多的第三方库中,工厂模式都十分常见。

在以往进行编程的时候,如果想要实现工厂模式,通常需要编写一个结构体,接着再去实现新的方法以及构建方法。然而,现在有厉害的开发者发布了 Bon 库。这个库能够让实现工厂模式变得非常轻松,只需要在你的代码中添加相应的注解,就能够自动生成代码。这样一来,就可以省去大量的时间。

bon是一个非常实用的 Rust 库。这个库主要用于为函数和结构体生成一种在编译时就能进行检查的构建器。通过使用“bon”库,开发人员可以更加高效地构建函数和结构体,并且在编译阶段就能够发现潜在的错误,从而提高代码的质量和可靠性。此外,“bon”库还为函数和方法提供了带有可选参数和命名参数的惯用部分应用。这种特性使得函数和方法的调用更加灵活,可以根据不同的需求进行参数的选择和组合,进一步增强了 Rust 代码的可扩展性和可维护性。

类似于 Java 中的 Lombok 库,当你在项目中使用了它之后,类的属性的 getter 和 setter 等功能便无需你亲自去编写了。而这里提到的“bon”,它的作用在于使得 builder 不用你自己去编写。Lombok 库为 Java 开发者带来了极大的便利,通过简化代码的编写过程,提高了开发效率。同样,“bon”在特定的场景下也发挥着重要的作用,为开发者省去了编写 builder 的繁琐工作,让开发过程更加流畅和高效。


一、安装Bon

将此内容添加到你的Cargo.toml以使用这个库:

[dependencies]
bon = "2.2.1"

在非标准环境(no_std environments)中,可以通过将 default-features 设置为 false 来选择不使用 std 和 alloc cargo 特性。

或者在你的项目下执行以下命令

cargo add bon

版本用最新的就好了,这里只是个示例。

二、使用步骤

1.为方法实现builder

bon 可以通过构建器将带有位置参数的函数转换为带有 “具名” 参数的函数。只需在函数上方放置 #[builder] 宏即可轻松实现。这意味着使用 bon 这个工具,对于原本使用位置参数的函数,可以通过特定的方式(添加 #[builder] 宏)将其转换为使用具名参数的函数形式,使得函数调用更加清晰和灵活。例如,原本可能需要按照特定顺序传入参数的函数,现在可以通过指定参数名称来传入参数(链式调用)。

use bon::builder;
// 只需要下面一行注解
#[builder] 
fn greet(name: &str, age: u32) -> String {
    format!("Hello {name} with age {age}!")
}

// 就可以实现链式调用
let greeting = greet()
    .name("Bon")
    .age(24)
    .call();

assert_eq!(greeting, "Hello Bon with age 24!");

这玩意儿也可以用在异步函数、可能出错的函数、泛型函数、“impl Trait”环境下,如果有问题你可以到git官方提交一个issue.

2.实现关联方法的builder

你也可以为关联方法生成构建器。要实现这一点,你还需要在 impl 代码块的上方添加一个 #[bon] 宏。

use bon::bon;

struct Counter {
    val: u32,
}

#[bon] // 在impl代码块上需要添加这个宏
impl Counter {
    #[builder] // 只要加了这个标记,调用时都是支持链式调用的
    fn new(initial: Option<u32>) -> Self {
        Self {
            val: initial.unwrap_or_default(),
        }
    }

    #[builder] 
    fn increment(&mut self, diff: u32) {
        self.val += diff;
    }
}

let mut counter = Counter::builder()
    .initial(3)
    .build();

counter
    .increment()
    .diff(3)
    .call();

assert_eq!(counter.val, 6);

在遵循 Rust 构建器的常见命名约定时,bon 对在 impl 代码块内部名为 new 的方法进行特殊处理。它会生成名称稍有不同的函数。

如果 #[builder] 被放置在名为 new 的方法上,那么生成的函数将通过builder()调用

对于不是名为 “new” 的任何其他方法以及任何自由函数通过call()调用。

3. 为结构体实现builder

bon支持经典模式,即使用 #[derive (Builder)] 语法对结构体进行标注以生成构建器。这意味着在 Rust 语言中,使用名为 bon 的 crate 时,可以通过在结构体上添加#[derive (Builder)]属性来自动生成一个构建器。这个构建器可以用于以一种更加灵活和可读的方式创建结构体的实例。例如,可以逐步设置结构体的各个字段,而不是一次性提供所有的参数。这样可以提高代码的可读性和可维护性,并且可以在构建过程中进行一些额外的验证或处理。例如

use bon::Builder;

#[derive(Builder)] // 添加这一行就够了
struct User {
    id: u32,
    name: String,
}

let user = User::builder()
    .id(1)
    .name("Bon".to_owned())
    .build();

assert_eq!(user.id, 1);
assert_eq!(user.name, "Bon");

在结构体上使用 #[derive (Builder)] 会生成构建器 API,这个 API 与在结构体的 new () 方法上放置 #[builder] 属性且该方法的签名与结构体的字段相似的情况完全兼容。

一般来说,在结构体上使用 #[derive(Builder)] 和在函数/方法上使用 #[builder] 具有几乎相同的应用程序接口(API)。在整个文档中会同时使用这两种方式来提供示例。如果示例中只展示了一种语法的用法(例如 #[builder]),那么在没有明确说明的情况下,另一种语法(例如 #[derive(Builder)])很可能具有类似的效果。

#builder#[derive(Builder)]生成的构建器使用类型状态模式来确保所有必需的参数都被填充,并且不会重复调用相同的设置器,以防止意外的覆盖和拼写错误。如果有问题,将会产生编译错误。在构建器内部不存在潜在的 panic unwrap()调用。

4. Option<T>字段成为可选项

如果你的函数参数或结构体字段(简称成员)是 Option类型,那么生成的构建器不会强制为这个成员设置值,默认值为 None。

它还会生成两个设置器:一个接受 T 类型的值,另一个接受 Option类型的值。第一个设置器在调用处避免用 Some()包裹值。第二个设置器允许直接传入 Option类型的值。

use bon::Builder;

#[derive(Builder)]
struct Projection {
    x: Option<u32>,
    y: Option<u32>,

    // 对非`Option`类型的成员使用注解。
    #[builder(default)]
    z: u32,
}

// “x”和“y”都将被设置为“None”,“z”将被设置为“0”。
Projection::builder().build();

Projection::builder()
    // 不使用`Some()`包裹值进行传递。
    .x(10)
    // 或者使用以“maybe_”为前缀的设置器,该设置器接受“Option”类型。
    .maybe_y(Some(20))
    // 对于`#[builder(default)]`和`Option<T>`生成的应用程序编程接口(API)是等效的。
    // 当调用`build()`时,`z`将被设置为`0`。
    .maybe_z(None)
    .build();

5. 实现Into转化

如果你的成员类型是 String 或者 PathBuf,并且你需要将它们设置为硬编码的字符串字面量,那么你必须编写.to_owned() 或者.to_string() 或者.into()。

在这里插入图片描述
然而,你可以使用 bon 生成接受 impl Into 的设置器,以消除手动转换的需要。这可以通过对单个成员使用 #[builder (into)] 进行配置,或者对多个成员同时使用 #[builder (on ({类型}, into))] 进行配置。

use bon::Builder;
use std::path::PathBuf;

// 所有类型为`String`的成员的设置器都将接受`impl Into<String>`。
#[derive(Builder)]                                                          
#[builder(on(String, into))]                                                
struct Project {
    name: String,
    description: String,

    // 此成员的唯一设置器将接受“实现了 Into<PathBuf> 的类型”。
    #[builder(into)]                                                       
    path: PathBuf,
}

Project::builder()
    // “&str”在内部被转换为“String”。
    .name("Bon")
    .description("Awesome crate 🐱")
    // “&str”在内部被转换为“PathBuf”。
    .path("/path/to/your/heart")
    .build();

这只是 bon 所提供功能的一部分。你可以考虑阅读指南部分的其余内容,以充分发挥 bon 的强大功能并理解其做出的决策。

参考文档

  • bon官方文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2124784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能制造云平台---附源码79117

目 录 摘要 1 绪论 1.1 研究背景和意义 1.2开发技术 1.2.1 Flask框架 1.2.2 Python简介 1.2.3 MySQL数据库 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2总体设计原则 2.3 系统流程分析 2.3.1 用户登录流程 2.3.2 删除信息流程 2.4 系统角色分析 2.5 系…

微信小程序 - 最新将页面可分享到朋友圈功能,小程序实现分享到朋友圈功能,开启分享给好友及分享朋友圈功能(微信小程序怎么分享到朋友圈?详细流程及示例代码教程)

前言 没有设置过分享朋友圈功能的小程序,分享朋友圈按钮是灰色且无法点击。 在微信小程序开发中,详解实现把页面开启朋友圈分享功能,解决 “当前页面未设置分享” 且灰色无法点击问题,微信小程序开发中的微信分享和朋友圈分享设置,提供详细代码。 小程序 vue2 | vue3 版本…

yum下载软件失败:‘Could not resolve host: mirrorlist .centos .org; Unknowm error

Loaded plugins: fastestmirror, ovl Determining fastest mirrors Could not retrieve mirrorlist http://mirrorlist.centos.org/?release7&archx86_64&repoos&infracontainer error was 14: curl#6 - “Could not resolve host: mirrorlist.centos.org; Unknow…

Games101图形学学习笔记——图形学基础

这里写目录标题 图形学基础线性代数Vector向量向量的点乘向量的叉乘 矩阵 Transform3D变换视图/相机变换 正交投影和透视投影正交投影透视投影 图形学基础 基础数学&#xff1a;线性代数&#xff0c;几何 基础物理&#xff1a;力学&#xff0c;光学 其他&#xff1a;信号处理&…

代码随想录训练营 Day56打卡 图论part06 108. 冗余连接 109. 冗余连接II

代码随想录训练营 Day56打卡 图论part06 一、卡码108. 冗余连接 题目描述 有一个图&#xff0c;它是一棵树&#xff0c;他是拥有 n 个节点&#xff08;节点编号1到n&#xff09;和 n - 1 条边的连通无环无向图&#xff08;其实就是一个线形图&#xff09;&#xff0c;如图&…

Java面试篇基础部分-Java的类加载机制

JVM的类加载 JVM在运行Java文件的时候,类加载分为5个阶段:加载、验证、准备、解析、初始化。在类初始化加载完成之后,就可以使用这个类的信息了。当这个类不需要使用的时候,就可以从JVM进行卸载。 加载 加载是指JVM读取Class文件的操作,并且根据Class的文件描述创建对应的…

工厂安灯系统在优化生产流程上的优势丨深圳讯鹏科技

工厂安灯系统通过可视化的方式&#xff0c;帮助工厂管理者和操作工人及时了解生产状态&#xff0c;快速响应问题&#xff0c;从而优化生产流程。 一、安灯系统实时监控与反馈 安灯系统的核心功能是实时监控生产线的状态。通过在生产现场设置灯光、显示屏等设备&#xff0c;工人…

单片机拍照_将采集的RGB图像封装为BMP格式保存到SD卡

文章目录 一、前言二、BMP文件结构2.1 BMP图片的格式说明 2.2 RGB888与RGB565格式是什么&#xff1f;&#xff08;1&#xff09;RGB565&#xff08;2&#xff09;RGB888&#xff08;3&#xff09;区别&#xff08;4&#xff09;如何构成&#xff08;5&#xff09;示例 三、实现…

yolo训练出现Could not load library libcudnn_cnn_train.so.8问题及解决方法

问题场景&#xff1a; 训练yolov5或者yolov8时候会报错&#xff1a; Could not load library libcudnn_cnn_train.so.8. Error: /usr/local/cuda-12.1/lib64/libcudnn_cnn_train.so.8: uined symbol: _ZN5cudnn3cnn34layerNormFwd_execute_internal_implERKNS_7backend11Vari…

【EasyExcel】@ColumnWidth(value = 20) EasyExcel设置列宽不生效

经过测试发现&#xff0c;只有XLS&#xff0c;ColumnWidth注解才会生效&#xff0c;选择CSV和XLSX都不会生效 //对应的导出实体类 EasyExcel.write(outputStream, Result.class)//excel文件类型&#xff0c;包括CSV、XLS、XLSX.excelType(ExcelTypeEnum.XLS)

当你学会了Python,随手爬取电影榜单!

一、爬电影TOP250 python爬取电影TOP250数据&#xff01; 首先&#xff0c;打开电影TOP250的页面&#xff1a; https://movie.douban.com/top250 开发好python代码后&#xff0c;成功后的csv数据&#xff0c;如下&#xff1a; 代码是怎样实现的爬取呢&#xff1f;下面逐一讲…

计算机网络相关概念

名词解释&#xff1a; 1.ARPANET ARPANET&#xff08;Advanced Research Projects Agency Network&#xff09;是由美国国防部高级研究计划局&#xff08;ARPA&#xff09;在1969年启动的一个实验性计算机网络项目。它是世界上第一个分组交换网络&#xff0c;也是互联网的前身…

springboot《计算机网络》在线考试系统-计算机毕业设计源码22248

摘要 计算机网络课程是计算机科学与技术、信息技术及相关专业的一门重要课程。然而&#xff0c;在传统的教育模式下&#xff0c;计算机网络课程的考核方式多以纸质试卷为主&#xff0c;这种方式存在诸多弊端。一方面&#xff0c;试卷的编制、印刷、分发、收缴等环节耗时耗力&am…

遗传算法求解VRP路径规划问题

文章目录 题目&#xff1a;快递公司送货策略VRP问题简介遗传算法项目地址代码说明代码结构求解流程举例求解目标求解步骤 总结 打数模国赛前拿来练手的题&#xff0c;现在题目求解思路分享给大家&#xff0c;包括 所有源代码 和 高清pdf论文&#xff0c;希望能对大家有所帮助…

多线程篇(其它容器- CopyOnWriteArrayList)(持续更新迭代)

一、CopyOnWriteArrayList&#xff08;一&#xff09; 1. 简介 并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList&#xff0c;对其进行的修改操作都是在底层的一个复制的数 组&#xff08;快照&#xff09;上进行的&#xff0…

解决 git 不是内部或外部命令,也不是可运行的程序

目录 报错提示&#xff1a; 一、解决办法 1、从git官网下载windows版本的git 2、安装 3、注意事项 二、报错 1、解决 fatal: Not a git repository (or any of the parent directories): .git 问题 报错提示&#xff1a; 一、解决办法 Windows下配置Git&#xff1a; 1…

sap公司间交易(采购单转储)-公司间交易价格的配置

sap 公司间交易(采购单转储)-公司间交易价格的配置 对于通过采购单转储方式实现公司间交易,公司间交易价系统标准设计是,购货方采用采购单上的单价做为发票校验的价格,而销售方由于没有销售单,则采用的是在 vk11 里维护的公司间售价,这种做法的坏处是经常要同步这两个价格…

error C2275: 将此类型用作表达式非法-解决方案

最近在进行将C移植C的项目&#xff0c;代码改完&#xff0c;生成解决方案时&#xff0c;出现如下错误&#xff1a; 在移植c代码到c的时候&#xff0c;经常会出现一个奇怪的错误&#xff1a;“error C2275: “xxxxx”: 将此类型用作表达式非法” 两个错误属于同一类型&#xff…

投资一家无人机培训机构技术详解

无人机培训机构是随着无人机技术的快速发展和普及而兴起的一种专业培训机构。这类机构专注于为学员提供无人机相关的理论知识、操控技能以及应用技术培训&#xff0c;以满足不同领域对无人机人才的需求。 1. 市场调研与定位 市场调研 在投资无人机培训机构之前&#xff0c;深…