Rust 第五天—代码组织管理

news2024/11/24 16:26:03

通过之前的内容介绍,对Rust或多或少有了一些了解.也许现在还不能写出“像样子”的项目,但是把大量代码堆积写在一个文件中依旧是不可取的.今天的内容相对轻松一些,聊聊Rust的模块

Rust的模块系统可以划分为Package,Crate,Module,具体可以总结如下:

  • Package:整个项目
  • Crate:编译时的最小代码单位,即可以编译为二进制可执行文件,也可以是库.
  • Module:模块,用于解耦逻辑功能代码

Package可以包含任意个二进制Crate,最多只能包含一个library Crate;同时,最少得包含一个Crate,无论是库还是二进制文件.

下面就通过一个例子来简单体会一下这种代码结构组织

首先按照惯例创建一个新的项目,只是这一次创建的不再是常规的二进制而是库cargo new crate-demo --lib,这样我们就得到了一个Package.

然后配置一下Cargo.toml,添加依赖以及包类型

[lib]
crate-type=["cdylib"]
​
[dependencies]
wasm-bindgen="0.2.87"

这里设置crate-type为cdylib,其实Rust构建lib有很多种type,我们可以通过rustc --help|grep crate-type进行查看

image-20230621111356656

这里稍作解释

  • bin: 二进制可执行文件,编译时有main函数作为入口会自动识别
  • lib: 是一种别名,没有具体表示
  • rlib: Rust lib静态库(不指定时默认值),用于纯Rust代码之间的依赖调用
  • dylib: 动态库,用于纯Rust代码之间调用
  • cdylib: C规范动态库,可提供给其他语言调用
  • staticlib:静态库,将所有代码以及依赖打包编译
  • proc-macro:过程宏,可以被其他crate调用

我们这里依赖wasm-bindgen相信熟悉的应该都知道了,这个demo是关于WebAssembly的,这也解释了为什么crate-type选择cdylib.构建好Package,我们就可以在crate内编写module,最终实现功能了.

这里我们的函数很简单,就是将i32的加减乘除封装一下,从而通过不同的flag对应不同的op进行计算.为了展示代码结构化,特意将各个op分开两两一组,最终的文件树如下

image-20230621152459900

这里分别使用ops.rs,add_mul.rs,sub_div.rs导出内部包,内容分别为pub mod xxx

image-20230621153323585

然后在各个子文件夹写算子计算函数,例如

image-20230621153426613

最后lib.rs中封装一下

use ops::add_mul::{add, mul};
use ops::sub_div::{div, sub};
use wasm_bindgen::prelude::*;
​
​
#[wasm_bindgen]
pub fn op_cal(flag:u8,a:i32,b:i32)->i32{
    match flag {
        1=>{add::add(a,b)}
        2=>{mul::mul(a,b)}
        3=>{sub::sub(a,b)}
        4=>{div::div(a,b)}
        _ => 0
    }
}

这里需要导入wasm相关依赖,具体可以去看官网介绍

完成这些,然后安装wasm-pack:cargo install wasm-pack,安装如果提示需要更新Rust,直接rustup update,并且为了防止编译报错,在.toml中加上

[package.metadata.wasm-pack.profile.release]
wasm-opt = false

万事俱备开始编译:wasm-pack build --target web

等待一会,编译之后可以看到多出一个pkg文件夹,里面包含了打包好的js,ts等文件.

image-20230621154352410

这里的op_cal就是我们Rust写的lib中封装的函数,然后再写一个前端html调用这个js试试.前端入门级,网上copy了一段代码稍微修改一下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Rust && WebAssembly Demo</title>
</head>
<body>
​
<table>
    <tr>
        <td><input type="button" value="add" onclick="setOp('+', 'add');"/></td>
        <td><input type="button" value="mul" onclick="setOp('*', 'mul');"/></td>
        <td><input type="button" value="sub" onclick="setOp('-', 'sub');"/></td>
        <td><input type="button" value="div" onclick="setOp('/', 'div');"/></td>
    </tr>
</table>
​
<table id="tb_calc">
    <tr>
        <td><input id="x" type="text"  value="" name="x" /></td>
        <td><lable id="op"  name="op"></lable> </td>
        <td><input id="y" type="text" value="" name="y" /> </td>
        <td><input id="opTips" type="button" value=""/> </td>
        <td><lable id="result" name="z" value="?"></lable> </td>
    </tr>
</table>
​
​
<script type="application/javascript">
    function setOp(op, opTips)
    {
        const tb = document.getElementById("tb_calc");
        tb.style.display = "none";
​
        document.getElementById("x").value = "";
        document.getElementById("y").value = "";
        document.getElementById("result").innerText = "";
        document.getElementById("op").innerText = op;
        document.getElementById("opTips").value = opTips;
​
        tb.style.display = "block";
    }
</script>
​
​
<script type="module">
    import init,{op_cal} from './pkg/crate_demo.js';
​
    const cal=async ()=>{
        await init();
        const x = parseInt(document.getElementById("x").value);
        const y = parseInt(document.getElementById("y").value);
        let op = document.getElementById("op").innerText;
        switch (op) {
            case '+':
                op=1;
                break;
            case '*':
                op=2;
                break;
            case '-':
                op=3;
                break;
            case '/':
                op=4;
                break;
        }
​
        const result=op_cal(parseInt(op),x,y);
        document.getElementById("result").innerText = result.toString();
    }
​
    let btn=document.getElementById('opTips');
    btn.addEventListener('click',cal,false);
</script>
</body>
</html>

用http-server运行看看效果

image-20230621154753058

image-20230621154807634

image-20230621154821264

image-20230621154836504

基本实现了目标,不过这个html的逻辑属实太烂.明明可以通过点击不同op实现不同计算而不是每次换个op就得重新输入,不过毕竟只是验证wasm打包后调用是否正常做个简单demo,也就没必要刻意优化.

总结

总的来说,Rust的代码组织文件系统还是比较人性化的,而且使用起来也比较容易上手.相比起go没有workspace之前引入本地包来说,这种体验简直不要太好.这里也有很多没有提到的,比如as别名,*self引入全部以及本身等等,这些其实在其他语言中或多或少都有相似之处,因此慢慢后期用到会稍微介绍一下.最后,我们用wasm实现了一个简单的四则运算,这里面更多是为了演示复杂文件路径的模块引入,所以直接固定类型为i32而没有用泛型来写,后续继续学习之后,会写一些复杂点的demo来参考学习.

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

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

相关文章

【hadoop】Linux安装和配置

安装 RedHat Linux 7.4 创建新的虚拟机 选择“自定义&#xff08;高级&#xff09;” 选择“下一步” 选择“稍后安装操作系统” 选择操作系统的类型 设置虚拟机名称和保存路径 下一步 下一步 设置网络类型&#xff0c;选择“使用仅主机模式网络” 下一步 下一步 下一步 设置硬…

pytorch笔记:归一化

来自B站视频&#xff0c;API查阅&#xff0c;TORCH.NN layer normalization 是针对单个样本&#xff0c;训练和测试的时候行为一致LN 相对于 BN 更适合 RNN&#xff0c;可以降低训练时间LN 中不同样本有不同的归一化参数&#xff0c;以层计算 a 是输入&#xff0c;f 是每层具…

【LeetCode周赛】2022上半年题目精选集——思维题

文章目录 2211. 统计道路上的碰撞次数&#xff08;栈 || 脑筋急转弯&#xff09;解法1&#xff1a;自己想的——使用栈解法2——思维&#xff1a;去掉左右两边往左右开的车代码写法1——找左右端点代码写法2——正则表达式去除流处理api补充&#xff1a;replaceAll() 和 正则表…

VS2022 And QtCreator10 调试 Qt 源码教程

文章目录 背景IDE 调试 Qt 源码Visual Studio 2022Qt Creator 10.0.1 排查思路姊妹篇系列 简 述&#xff1a; 记录使用 Visual Studo 2022 和 QtCreator10 调试 Qt 5.15 源码和 加载 .pdb 的方法。 本文初发于 “偕臧的小站”&#xff0c;同步转载于此。 背景 源码&#xff1a;…

8、动手学深度学习——现代卷积神经网络:AlexNet

1、学习表征 在2012年前&#xff0c;图像特征都是机械地计算出来的。事实上&#xff0c;设计一套新的特征函数、改进结果&#xff0c;并撰写论文是盛极一时的潮流 另一组研究人员&#xff0c;包括Yann LeCun、Geoff Hinton、Yoshua Bengio、Andrew Ng、Shun ichi Amari和Juer…

Java阶段四Day11

Java阶段四Day11 文章目录 Java阶段四Day11Spring AOPElasticsearch1. 关于各种数据库的使用2. 关系型数据库中的索引3. 安装与启动elasticsearch4. 访问elasticsearch5. 使用elasticsearch分词6. elasticsearch文档的相关概念7. 使用elasticsearch添加数据7.1. 添加文档7.2. 查…

Spring Boot 中的分布式追踪及使用

Spring Boot 中的分布式追踪及使用 随着互联网应用程序的复杂性不断增加&#xff0c;分布式系统已经成为了许多企业级应用程序的标配。在分布式系统中&#xff0c;由于服务之间的调用关系错综复杂&#xff0c;很难追踪到一个请求在整个系统中的执行路径和时间&#xff0c;这就…

Python如何提高工作效率,轻松实现读取分数,计算出最高/低分

前言 Python如何读取分数&#xff0c;计算最高/低分 与平均分&#xff1f; 今天这篇文章就来带你学习学习如何实现这个功能~ 环境使用: Python 3.8 解释器 Pycharm 编辑器 涉及知识点 文件读写基础语法字符串处理循环遍历 代码展示 模块 import platform定义获取最高分、最…

AI 语音 - 人声歌曲合成

前情提要 2023-07-02 周日 杭州 阴晴不定 小记: 天生五音不全&#xff0c;唱歌永远找不到调&#xff0c;使用下 AI 通过音色合成下吧&#xff0c;目前才训练 15000 步左右&#xff0c;我准备的数据集其实满打满算也只有 40min 左右的数据集&#xff0c;为了数据预处理有删减了…

基于openvino+yolov5的模型量化记录(PTQ模式)

本文主要是记录学习openvino_notebootk 302-pytorch-quantization-aware-training文档的一些收获&#xff0c;对于yolov5在cpu部署感兴趣的可以参考下。 此文档的目的是为了了解openvino如何降低模型部署的推理时间&#xff0c;同时尽可能保证精度。 此文档一共提供了两种PT…

【Flutter】Flutter 使用 Stream Transform 包处理流操作

文章目录 一、 前言二、 Stream Transform 包简介三、 安装和版本信息四、 Stream Transform 的基本使用1. 扩展方法2. 异步映射 五、 示例&#xff1a;使用 Stream Transform 实现实时搜索功能六、 总结 一、 前言 欢迎来到我的博客&#xff01;我是小雨青年&#xff0c;这是…

基于docker的ubuntu云服务器jupyter深度学习环境配置指南

step1 安装docker 文档中的命令如下&#xff1a; sudo apt-get update sudo apt-get install ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings…

驱动 控制开发版3盏灯、蜂鸣器、风扇、马达

head.h #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t; //查看开发扩展板原理图可知 //蜂鸣器 PB6 //风扇 PE9 //马达 PF6 //LED1 PE…

商用车线控底盘需求文档

一、 概述 商用车线控底盘主要用于接收智能驾驶域控制器&#xff08;控制器ADU&#xff09;的请求指令&#xff0c;完成ADU 对驱动、制动、档位转向、驻车声光等部分的指令控制&#xff0c;从而实现智能驾驶功。 即 ADU 可通过 CAN 通讯的方式以特定周期和指令控制 一台车的线控…

驱动开发作业2 —— ioctl

通过ioctl函数选择不同硬件的控制&#xff0c;如实现对LED、蜂鸣器、马达、风扇的控制 1.将GPIO的相关寄存器封装成结构体 --------> gpio.h 2.LED相关驱动文件 --------> led.c 3.蜂鸣器相关驱动文件 --------> beep.c 4.风扇相关驱动文件 --------> fan.c 5.马…

Ubuntu/Debian等Linux系统安装微信客户端

【写在前面】 由于本人的工作环境基本是在ubuntu下&#xff0c;而ubuntu使用网页版微信常常会出现无法登陆的现象&#xff0c;为了能够在linux系统用上微信&#xff0c;于是在网上找了找办法&#xff0c;没想到还真有大神做了&#xff0c;特此分享出来。 【安装步骤】 其实只…

UNIX网络编程卷一 学习笔记 第二十二章 高级UDP套接字编程

TCP是一个字节流协议&#xff0c;又使用滑动窗口&#xff0c;因此没有记录边界或发送者数据发送能力超过接收者接受能力之类的事情&#xff0c;但对于UDP&#xff0c;每个输入操作对应一个UDP数据报&#xff08;一个记录&#xff09;&#xff0c;因此当收取的数据报大于引用的输…

软件测试--Fiddler的使用(持续更新)

1.工具界面介绍 2.抓取请求 打开Fiddler,随便访问一些网址,左边便会抓取到很多请求 3.删除请求(Remove all或者输入命令) 4.过滤请求 ps: 5.打开抓HTTPS设置 6.界面熟悉 7.抓包图标说明

MPC vs Multi-sig——误解及重点关注

1. 引言 资金托管的2大主流方案为&#xff1a; MPC&#xff1a;MPC钱包——对应EOA账号。用于高信任企业场景。Multi-sig&#xff1a;多签钱包——对应智能合约钱包。用于个人场景&#xff0c;可强化安全性并易于恢复。 不过V神认为&#xff0c;基于MPC的EOA账号存在根本性缺…

不变的誓言 字符串常量

## 不变的誓言 字符串常量字符串常量&#xff0c;这节课的主题、 水帘洞一直都没有变1.什么是字符串呢&#xff1f; 就是一个一个字符连起来就是字符串&#xff0c;qq聊天 都是字符串。 字符串常量&#xff0c;“”1.什么是字符串呢&#xff1f; 就是一个一个字符连起来就是字…