likes
comments
collection
share

Rust 第五天—代码组织管理

作者站长头像
站长
· 阅读数 18

通过之前的内容介绍,对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进行查看

Rust 第五天—代码组织管理

这里稍作解释

  • 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分开两两一组,最终的文件树如下

Rust 第五天—代码组织管理

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

Rust 第五天—代码组织管理

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

Rust 第五天—代码组织管理

最后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等文件.

Rust 第五天—代码组织管理

这里的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运行看看效果

Rust 第五天—代码组织管理

Rust 第五天—代码组织管理

Rust 第五天—代码组织管理

Rust 第五天—代码组织管理

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

总结

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

转载自:https://juejin.cn/post/7247010613741617207
评论
请登录