Rust-AOP编程实战

news2024/11/13 19:50:24

文章本天成,妙手偶得之。粹然无疵瑕,岂复须人为?君看古彝器,巧拙两无施。汉最近先秦,固已殊淳漓。胡部何为者,豪竹杂哀丝。后夔不复作,千载谁与期?

——《文章》宋·陆游

【哲理】文章本是不加人工,天然而成的,是技艺高超的人在偶然间所得到的。其实作者所说的“天成”,并不就是大自然的恩赐,而是基于长期积累起来的感性印象和深入的思考,由于偶然出发而捕捉到灵感。

灵感就是长时间的积累和瞬间的爆发,人品也是,成就亦如是。

一、AOP 的概念

面向方面编程(Aspect-Oriented Programming,AOP)是一种编程范式,旨在通过将横切关注点(cross-cutting concerns)分离出来,从而提高代码的模块化和可维护性。横切关注点是指那些影响多个模块的功能,比如日志记录、安全检查、事务管理等。在传统的面向对象编程(OOP)中,这些关注点往往会散布在各个类中,导致代码重复和难以维护。

AOP 通过引入“方面”(aspect)的概念,将这些横切关注点集中到一个地方进行管理。主要的 AOP 概念包括:

  1. Aspect(方面):封装横切关注点的模块。
  2. Join Point(连接点):程序执行过程中可以插入方面的具体点,比如方法调用或异常抛出。
  3. Advice(通知):在特定的连接点上执行的代码,可以分为前置通知(Before)、后置通知(After)和环绕通知(Around)。
  4. Pointcut(切入点):定义在哪些连接点上应用通知的表达式。
  5. Weaving(织入):将方面应用到目标对象的过程,可以在编译时、加载时或运行时进行。

二、使用 Rust 实现 AOP

虽然 Rust 没有直接支持 AOP,但我们可以通过宏和闭包来实现类似的效果。

1、声明宏实现 AOP

1.1、定义宏和函数

首先,我们定义一个宏,用于在函数调用前后执行一些额外的逻辑:

macro_rules! aop {
    ($func:expr, $before:expr, $after:expr) => {
  {
        $before();
        let result = $func();
        $after();
        result
    }};
}

这个宏接受三个参数:

  • $func:要调用的函数。
  • $before:在函数调用前执行的闭包。
  • $after:在函数调用后执行的闭包。

1.2、使用宏实现 AOP

接下来,我们定义一些示例函数和通知,并使用 aop! 宏来包装函数调用:

fn main() {
    // 定义前置通知
    let before = || println!("Before function call");

    // 定义后置通知
    let after = || println!("After function call");

    // 定义一个示例函数
    let my_function = || {
        println!("Inside the function");
        42 // 返回一些值
    };

    // 使用 aop! 宏包装函数调用
    let result = aop!(my_function, before, after);
    println!("Function returned: {}", result);
}

运行这个程序,你会看到以下输出:

Before function call
Inside the function
After function call
Function returned: 42

1.3、环绕通知

为了更好地展示 AOP 的灵活性,我们可以扩展示例,添加更多的通知类型,比如环绕通知:

macro_rules! aop_around {
    ($func:expr, $around:expr) => {
  {
        $around($func)
    }};
}

fn main() {
    // 定义环绕通知
    let around = |func: fn() -> i32| {
        println!("Before function call (around)");
        let result = func();
        println!("After function call (around)");
        result
    };

    // 定义一个示例函数
    let my_function = || {
        println!("Inside the function");
        42 // 返回一些值
    };

    // 使用 aop_around! 宏包装函数调用
    let result = aop_around!(my_function, around);
    println!("Function returned: {}", result);
}

运行这个扩展示例,你会看到以下输出:

Before function call (around)
Inside the function
After function call (around)
Function returned: 42

1.4、更精确的切入点定义

定义宏和函数

首先,我们定义一个宏,用于在函数调用前后执行一些额外的逻辑,并允许通过条件判断来决定是否应用通知:

macro_rules! aop {
    ($func:expr, $before:expr, $after:expr, $pointcut:expr) => {
  {
        if $pointcut() {
            $before();
        }
        let result = $func();
        if $pointcut() {
            $after();
        }
        result
    }};
}

这个宏接受四个参数:

  • $func:要调用的函数。
  • $before:在函数调用前执行的闭包。
  • $after:在函数调用后执行的闭包。
  • $pointcut:一个返回布尔值的闭包,用于决定是否应用通知。
使用宏实现更精确的切入点

接下来,我们定义一些示例函数和通知,并使用 aop! 宏来包装函数调用,同时定义切入点条件:

fn main() {
    // 定义前置通知
    let before = || println!("Before function call");

    // 定义后置通知
    let after = || println!("After function call");

    // 定义一个示例函数
    let my_function = || {
        println!("Inside the function");
        42 // 返回一些值
    };

    // 定义切入点条件
    let pointcut = || true; // 可以根据需要修改条件

    // 使用 aop! 宏包装函数调用
    let result = aop!(my_function, before, after, pointcut);
    println!("Function returned: {}", result);
}

运行这个程序,你会看到以下输出:

Before function call
Inside the function
After function call
Function returned: 42

如果我们修改切入点条件,使其返回 false,则通知不会被应用:

fn main() {
    // 定义前置通知
    let before = || println!("Before function call");

    // 定义后置通知
    let after = || println!("After function call");

    // 定义一个示例函数
    let my_function = || {
        println!("Inside the function");
        42 // 返回一些值
    };

    // 定义切入点条件
    let pointcut = || false; // 修改条件

    // 使用 aop! 宏包装函数调用
    let result = aop!(my_function, before, after, pointcut);
    println!("Function returned: {}", result);
}

运行这个程序,你会看到以下输出:

Inside the function
Function returned: 42

扩展切入点条件

为了更灵活地定义切入点条件,我们可以将条件逻辑扩展为更加复杂的表达式。例如,我们可以根据函数名称、参数类型或其他上下文信息来决定是否应用通知。

fn main() {
    // 定义前置通知
    let before = || println!("Before function call");

    // 定义后置通知
    let after = || println!("After function call");

    // 定义多个示例函数
    let my_function1 = || {
        println!("Inside function 1");
        42 // 返回一些值
    };

    let my_function2 = || {
        println!("Inside function 2");
        24 // 返回一些值
    };

    // 定义切入点条件
    let pointcut = |func_name: &str| func_name == "my_function1";

    // 使用 aop! 宏包装函数调用
    let result1 = aop!(my_function1, before, after, || pointcut("my_function1"));
    println!("Function 1 returned: {}", result1);

    let result2 = aop!(my_function2, before, after, || pointcut("my_function2"));
    println!("Function 2 returned: {}", result2);
}

运行这个程序,你会看到以下输出:

Before functi

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

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

相关文章

深入了解支持向量机:机器学习中的经典算法

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

第01章 Linux概述及系统环境搭建

目标: ◆ 知道 Linux 是什么?有什么特点? ◆ 知道 Linux 内核及发行版的区别 ◆ 知道 Linux 的应用领域 ◆ 能够在虚拟机软件上新建虚拟机 ◆ 能够在虚拟机中挂载CentOS6.7光盘镜像 ◆ 能够根据需求安装CentOS6.7的操作系统 ◆ 能够对系统进行登录和关闭…

【题解】—— LeetCode一周小结45

🌟欢迎来到 我的博客 —— 探索技术的无限可能! 🌟博客的简介(文章目录) 【题解】—— 每日一道题目栏 上接:【题解】—— LeetCode一周小结44 4.平方数之和 题目链接:633. 平方数之和 给定一…

Python爬虫基础-正则表达式!

前言 正则表达式是对字符串的一种逻辑公式,用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则的字符串”,此字符串用来表示对字符串的一种“过滤”逻辑。正在在很多开发语言中都存在,而非python独有。对其知识点…

kdump 应该怎么安装 linux-crashdump kdump-tools

sudo apt install linux-crashdump sudo apt install crash sudo apt install kdump-tools 1. 两个工具的关系 linux-crashdump kdump-tools 在 Ubuntu 上安装 kdump 功能,这两个包都是相关的,但有不同的作用. linux-crashdump 是一个元包(…

STM32F405RGT6单片机原理图、PCB免费分享

大学时机创比赛时画的板子,比到一半因为疫情回家,无后续,,,已打板验证过,使用stm32f405rgt6做主控 下载文件资源如下 原理图文件 pcb文件 外壳模型文件 stm32f405例程 功能 以下功能全部验证通过 4路…

2024-11-01 - 统一身份认证 - OpenLdap - 中间件 - 流雨声

摘要 2024-11-01 周五 杭州 暴雨 调查问卷: https://www.wjx.cn/vm/exIBFDM.aspx# 2024年转瞬即逝,可是生活还在继续,这里有一项关于人工智能和项目管理对于效能关系的调研问卷,AI 对工作的作用和影响。问卷不采集个人信息,在此…

基于微信小程序的电商平台+LW示例参考

1.项目介绍 系统角色:管理员、普通用户功能模块:管理员(用户管理、商品分类、商品管理、订单管理、系统管理等),普通用户(个人中心、收藏、我的订单、查看商品等)技术选型:SpringBo…

python读取word的自动编号以及添加自动编号

目录 1、读取编号 读取示例 如何判断段落是否有自动编号呢? 如何区分不同的类型编号呢? 2、添加自动编号 有的时候需要提取word中带自动编号的信息。对于word中的文字很多第三方的库都可以搞定,但是,提取格式,可能…

ImportError: cannot import name ‘packaging‘ from ‘pkg_resources‘ 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境: Ubuntu20.04 ROS-Noetic 一、问题描述 自己在通过 pip install 安装module时 (使用的是 pip install mmcv)遇到如下问题: ImportError: cannot …

【论文笔记】Wings: Learning Multimodal LLMs without Text-only Forgetting

🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Wings: Learning Multimod…

Tomasulo算法介绍

Tomasulo算法详细解释 #mermaid-svg-x5G4yi740f0ju3OB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-x5G4yi740f0ju3OB .error-icon{fill:#552222;}#mermaid-svg-x5G4yi740f0ju3OB .error-text{fill:#552222;strok…

【C++练习】二进制到十进制的转换器

题目:二进制到十进制的转换器 描述 编写一个程序,将用户输入的8位二进制数转换成对应的十进制数并输出。如果用户输入的二进制数不是8位,则程序应提示用户输入无效,并终止运行。 要求 程序应首先提示用户输入一个8位二进制数。…

量子计算包kaiwu安装过程踩过的坑

目录 1 安装过程 2 官方代码测试 3 踩坑说明 首先,目前的kaiwu版本仅支持python3.8,所以必须要下载python3.8才能运行kaiwu 1 安装过程 step1: 在页面的SDK标签下,找到对应操作系统的kaiwu包。 step2: 下载python3.8到本地,可…

全文检索ElasticSearch到底是什么?

学习ElasticSearch之前,我们先来了解一下搜索 1 搜索是什么 ① 概念:用户输入想要的关键词,返回含有该关键词的所有信息。 ② 场景: ​ 1互联网搜索:谷歌、百度、各种新闻首页; ​ 2 站内搜索&#xff…

海鲜特写镜头视频素材去哪找 热门视频素材网站分享

作为美食自媒体创作者,海鲜特写镜头的视频素材无疑是提升内容吸引力和质量的重要利器。无论你想展示新鲜的海鲜原料、精美的烹饪过程,还是诱人的餐桌美食,精致的海鲜特写镜头都能极大地吸引观众的注意力。那么,问题来了&#xff1…

Unity 如何优雅的限定文本长度, 包含对特殊字符,汉字,数字的处理。实际的案例包括 用户昵称

常规限定文本长度 ( 通过 UntiyEngine.UI.Inputfiled 附带的长度限定 ) 痛点1 无法对中文,数字,英文进行识别,同样数量的汉字和同样数量的英文像素长度是不一样的,当我们限定固定长度后,在界面上的排版不够美观 痛点2…

SH3001姿态解算

姿态角,机体坐标系相对于参考坐标系的角度 旋转的非交换性 姿态角指的是载体坐标系与参考系之间的关系, 欧拉角是描述物体与某个轴(X,Y,Z)的关系,欧拉角属于姿态角的一种常见描述形式,另外两种描述形式就是四元数和和旋转矩阵 飞…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-19

文件下载与邀请翻译者 学习英特尔开发手册,最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册,会是一件耗时费力的工作。如果有愿意和我一起来做这件事的,那么&#xff…