在日常业务开发中,我们经常需要基于一些“规则”来决定程序的走向。比如:

  • 客服机器人 根据用户问题领域和复杂度选择不同的模型;
  • 营销系统 根据用户画像匹配不同优惠券;
  • 风控引擎 根据请求参数、时间、分值判定是否放行。

这些规则往往以「条件 + 条件组 + 规则」的形式组织,支持 AND/OR 逻辑、字符串匹配、数值比较、日期比较、布尔运算等。
本文将手把手带大家实现一个可扩展的规则解析引擎,最终效果如下:

  • 支持 EQUALS / NOT_EQUALS / CONTAINS / IN / GREATER_THAN / LESS_THAN / REGEX 多种运算符;
  • 支持 STRING / NUMBER / DATE / BOOLEAN 多种数据类型;
  • 逻辑解析采用“AND 优先于 OR”的优先级;
  • 短路求值:在 AND 为 false 或 OR 为 true 时提前结束计算;
  • 代码可嵌入 Spring Boot,对接 REST API。

(完整项目代码附在文末,感兴趣的小伙伴可以自取hh~)


一、规则结构设计

我们将规则分为三层:

  1. 条件(Condition):原子判断,如「问题领域 == 编译原理」。
  2. 条件组(Group):由多个条件组成,内部支持 AND/OR。
  3. 规则(Rule):由多个条件组组成,组之间也支持 AND/OR。

在这里插入图片描述

前端传参示例(JSON):

{"rule": {"groups": [{"groupsOperator": "","conditions": [{ "field": "问题领域", "operator": "EQUALS", "value": "编译原理", "fieldType": "STRING", "groupOperator": "" },{ "field": "问题类别", "operator": "IN", "value": "静态分析,代码优化", "fieldType": "STRING", "groupOperator": "AND" },{ "field": "问题名称", "operator": "EQUALS", "value": "编译优化", "fieldType": "STRING", "groupOperator": "OR" }]},{"groupsOperator": "AND","conditions": [{ "field": "score", "operator": "GREATER_THAN", "value": "0.9", "fieldType": "NUMBER", "groupOperator": "" }]}]},"context": {"问题领域": "语法分析","问题类别": "LR","问题名称": "编译优化","score": 0.91}
}

对应逻辑表达式:

((问题领域 == 编译原理 AND 问题类别 ∈ {静态分析,代码优化}) OR 问题名称 == 编译优化)
AND (score > 0.9)

二、关键实现思路

1. 工具类(类型解析与容错)

  • 字符串转数字、日期、布尔值时采用 Optional,解析失败直接返回空。
  • IN 运算符支持逗号分隔。
  • REGEX 支持动态编译正则。

2. 条件求值器

负责判断单条条件是否成立:

  • STRING: equals/contains/in/regex
  • NUMBER: equals/greater/less/in
  • DATE: equals/greater/less/in
  • BOOLEAN: equals/not equals

3. 逻辑解析 —— AND 优先于 OR

这是本引擎的核心:

  • 错误做法:简单从左到右短路,会把 (A AND B) OR C 错判成 (A AND B) 不成立直接 false。

  • 正确做法先按 OR 分块,块内做 AND,再对块结果做 OR。

    • 条件层:cond[0] groupOperator cond[1] ...
    • 规则层:group[0] groupsOperator group[1] ...

算法逻辑:

// AND 优先级高于 OR : 按照 OR 切块,块内做 AND,块间做 OR
Boolean currentAnd = null;  // 当前块的累计结果
boolean anyOrTrue = false;  // 之前是否已有 AND 块为 True (用于整体 OR)for (元素 e : 序列) {if (第一个元素) {  // 第一个条件,开启 AND 块currentAnd = eval(e);continue;}if (连接符是AND) {  // AND:块内与currentAnd = currentAnd && eval(e);} else { // OR:结束上一个 AND 块,合入总结果anyOrTrue = anyOrTrue || Boolean.TRUE.equals(currentAnd);if (anyOrTrue) return true; // OR短路currentAnd = eval(e); // 开新 AND 块}
}
// 合并最后一块
anyOrTrue = anyOrTrue || Boolean.TRUE.equals(currentAnd);
return anyOrTrue;

三、代码示例

以条件组求值为例(AND > OR):

private boolean evalGroup(RuleDetailVO.GroupVO group, Map<String, Object> ctx) {List<RuleDetailVO.CondVO> conds = group.getConditions();if (conds == null || conds.isEmpty()) return false;Boolean currentAnd = null;boolean anyOrTrue = false;for (int i = 0; i < conds.size(); i++) {RuleDetailVO.CondVO c = conds.get(i);boolean curr = condEval.test(c, ctx);String join = c.getGroupOperator();boolean isOrJoin = RuleEvalUtils.isOr(join);if (i == 0) {currentAnd = curr;continue;}if (!isOrJoin) { // ANDcurrentAnd = currentAnd && curr;} else {         // ORanyOrTrue = anyOrTrue || Boolean.TRUE.equals(currentAnd);if (anyOrTrue) return true;currentAnd = curr;}}anyOrTrue = anyOrTrue || Boolean.TRUE.equals(currentAnd);return anyOrTrue;
}

规则层求值同理,只是把元素换成


四、测试用例

测试例1:

POST http://localhost:8080/api/rules/match

Content-Type:application/json

{"rule": {"groups": [{"groupsOperator": "","conditions": [{ "field": "问题领域", "operator": "EQUALS", "value": "编译原理", "fieldType": "STRING", "groupOperator": "" },{ "field": "问题类别", "operator": "IN", "value": "静态分析,代码优化", "fieldType": "STRING", "groupOperator": "AND" },{ "field": "问题名称", "operator": "EQUALS", "value": "编译优化", "fieldType": "STRING", "groupOperator": "OR" }]},{"groupsOperator": "AND","conditions": [{ "field": "score", "operator": "GREATER_THAN", "value": "0.9", "fieldType": "NUMBER", "groupOperator": "" }]}]},"context": {"问题领域": "语法分析","问题类别": "LR","问题名称": "编译优化","score": 0.91}
}

响应体:

{"hit": true
}

测试例2:

POST http://localhost:8080/api/rules/match

Content-Type:application/json

{"rule": {"groups": [{"groupsOperator": "","conditions": [{ "field": "问题领域", "operator": "EQUALS", "value": "编译原理", "fieldType": "STRING", "groupOperator": "" },{ "field": "问题类别", "operator": "IN", "value": "静态分析,代码优化", "fieldType": "STRING", "groupOperator": "AND" },{ "field": "问题名称", "operator": "EQUALS", "value": "编译优化", "fieldType": "STRING", "groupOperator": "OR" }]},{"groupsOperator": "AND","conditions": [{ "field": "score", "operator": "GREATER_THAN", "value": "0.9", "fieldType": "NUMBER", "groupOperator": "" }]}]},"context": {"问题领域": "语法分析","问题类别": "LR","问题名称": "编译优化","score": 0.91}
}

响应体:

{"hit": false
}

五、读者可进一步扩展

  1. 枚举化运算符

    • 避免拼写错误,支持自动校验。
  2. Bean Validation

    • 校验前端传参是否合法(如 fieldType 必须在 ENUM 内)。
  3. 规则预编译

    • 将规则提前编译为 Predicate<Map<String,Object>>,执行时直接调用,提升性能。
  4. 匹配路径审计

    • 记录每条条件的判断结果,用于调试与可视化。

六、总结

本文实现了一个 高可扩展的规则解析引擎,核心亮点:

  • 类型多样化:支持字符串、数字、日期、布尔;
  • 运算符丰富:equals、contains、in、regex、比较运算;
  • 逻辑正确性:严格保证 AND 优先于 OR,避免短路误判;
  • 短路优化:提升性能;
  • 可扩展性:支持与 Spring Boot 集成、缓存、审计等功能。

通过这种设计,我们可以在实际业务场景中灵活定义规则,既满足 前端可配置化,又保证 后端执行的确定性和高效性


附项目完整代码:

目录结构如下

rule-engine-springboot/
├─ pom.xml
└─ src/└─ main/├─ java/│  └─ per/│     └─ mjn/│        ├─ RuleEngineApplication.java│        ├─ common/│        │  └─ vo/│        │     └─ RuleDetailVO.java│        ├─ engine/│        │  ├─ ConditionEvaluator.java│        │  ├─ RuleEngine.java│        │  └─ RuleEvalUtils.java│        └─ web/│           ├─ MatchController.java│           └─ dto/│              ├─ MatchRequest.java│              └─ MatchResponse.java└─ resources/└─ application.yml

RuleDetailVO.java

package per.mjn.common.vo;import lombok.Data;import java.util.ArrayList;
import java.util.List;@Data
public class RuleDetailVO {private List<GroupVO> groups = new ArrayList<>();@Datapublic static class GroupVO {private String groupsOperator;private List<CondVO> conditions;}@Datapublic static class CondVO {private String field;private String operator;private String value;private String fieldType;private String groupOperator;}
}

ConditionEvaluator.java

package per.mjn.engine;import per.mjn.common.vo.RuleDetailVO;import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;public class ConditionEvaluator {public boolean test(RuleDetailVO.CondVO cond, Map<String, Object> ctx) {final String field = RuleEvalUtils.normField(cond.getField());final String op = cond.getOperator();final String fieldType = cond.getFieldType();final String expect = cond.getValue();final Object actual = ctx.get(field);if (!RuleEvalUtils.hasText(field) || !RuleEvalUtils.hasText(op)) return false;return switch (fieldType == null ? "STRING" : fieldType.toUpperCase()) {case "NUMBER" -> compareNumber(op, actual, expect);case "DATE" -> compareDate(op, actual, expect);case "BOOLEAN" -> compareBoolean(op, actual, expect);default -> compareString(op, actual, expect);};}private boolean compareString(String op, Object actual, String expect) {String a = RuleEvalUtils.asString(actual);if (a == null || expect == null) return false;return switch (op) {case "EQUALS" -> a.equals(expect);case "NOT_EQUALS" -> !a.equals(expect);case "CONTAINS" -> a.contains(expect);case "IN" -> RuleEvalUtils.parseInList(expect).contains(a);case "REGEX" -> Pattern.compile(expect).matcher(a).find();default -> false;};}private boolean compareNumber(String op, Object actual, String expect) {Optional<BigDecimal> aOpt = RuleEvalUtils.asDecimal(actual);Optional<BigDecimal> eOpt = RuleEvalUtils.asDecimal(expect);if (aOpt.isEmpty() || eOpt.isEmpty()) return false;BigDecimal a = aOpt.get();BigDecimal e = eOpt.get();int cmp = a.compareTo(e);return switch (op) {case "EQUALS" -> cmp == 0;case "NOT_EQUALS" -> cmp != 0;case "GREATER_THAN" -> cmp > 0;case "LESS_THAN" -> cmp < 0;case "IN" -> RuleEvalUtils.parseInList(expect).stream().anyMatch(s -> RuleEvalUtils.asDecimal(s).map(v -> v.compareTo(a) == 0).orElse(false));default -> false;};}private boolean compareBoolean(String op, Object actual, String expect) {Optional<Boolean> aOpt = RuleEvalUtils.asBoolean(actual);Optional<Boolean> eOpt = RuleEvalUtils.asBoolean(expect);if (aOpt.isEmpty() || eOpt.isEmpty()) return false;boolean a = aOpt.get();boolean e = eOpt.get();return switch (op) {case "EQUALS" -> a == e;case "NOT_EQUALS" -> a != e;default -> false;};}private boolean compareDate(String op, Object actual, String expect) {Optional<LocalDate> aOpt = RuleEvalUtils.asDate(actual);Optional<LocalDate> eOpt = RuleEvalUtils.asDate(expect);if (aOpt.isEmpty() || eOpt.isEmpty()) return false;LocalDate a = aOpt.get();LocalDate e = eOpt.get();int cmp = a.compareTo(e);return switch (op) {case "EQUALS" -> cmp == 0;case "NOT_EQUALS" -> cmp != 0;case "GREATER_THAN" -> cmp > 0;case "LESS_THAN" -> cmp < 0;case "IN" -> RuleEvalUtils.parseInList(expect).stream().anyMatch(s -> RuleEvalUtils.asDate(s).map(v -> v.compareTo(a) == 0).orElse(false));default -> false;};}
}

RuleEngine.java

package per.mjn.engine;import per.mjn.common.vo.RuleDetailVO;import java.util.List;
import java.util.Map;public class RuleEngine {private final ConditionEvaluator condEval = new ConditionEvaluator();public boolean matches(RuleDetailVO rule, Map<String, Object> ctx) {List<RuleDetailVO.GroupVO> groups = rule.getGroups();if (groups == null || groups.isEmpty()) return false;Boolean currentAnd = null;boolean anyOrTrue = false;for (int i = 0; i < groups.size(); i++) {RuleDetailVO.GroupVO g = groups.get(i);boolean curr = evalGroup(g, ctx);String join = g.getGroupsOperator();boolean isOrJoin = RuleEvalUtils.isOr(join);if (i == 0) {currentAnd = curr;continue;}if (!isOrJoin) {currentAnd = currentAnd && curr;} else {anyOrTrue = anyOrTrue || currentAnd;if (anyOrTrue) return true;currentAnd = curr;}}anyOrTrue = anyOrTrue || currentAnd;return anyOrTrue;}private boolean evalGroup(RuleDetailVO.GroupVO group, Map<String, Object> ctx) {List<RuleDetailVO.CondVO> conds = group.getConditions();if (conds == null || conds.isEmpty()) return false;// AND 优先级高于 OR : 按照 OR 切块,块内做 AND,块间做 ORBoolean currentAnd = null;  // 当前块的累计结果boolean anyOrTrue = false;  // 之前是否已有 AND 块为 True (用于整体 OR)for (int i = 0; i < conds.size(); i++) {RuleDetailVO.CondVO c = conds.get(i);boolean curr = condEval.test(c, ctx);String join = c.getGroupOperator();  // 当前条件与“上一条”的连接符boolean isOrJoin = RuleEvalUtils.isOr(join);if (i == 0) {  // 第一个条件,开启 AND 块currentAnd = curr;continue;}if (!isOrJoin) {  // AND 块内与currentAnd = currentAnd && curr;} else {  // OR:结束上一个 AND 块,合入总结果anyOrTrue = anyOrTrue || currentAnd;if (anyOrTrue) return true; // OR 短路currentAnd = curr;  // 开新 AND 块}}// 合并最后一个 AND 块anyOrTrue = anyOrTrue || currentAnd;return anyOrTrue;}
}

RuleEvalUtils.java

package per.mjn.engine;import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;public final class RuleEvalUtils {private RuleEvalUtils() {}public static boolean hasText(String s) {return s != null && !s.isBlank();}public static boolean isOr(String op) {return "OR".equalsIgnoreCase(op);}public static String normField(String f) {return f == null ? "" : f.trim();}public static List<String> parseInList(String v) {if (v == null) return List.of();String[] arr = v.split(",");List<String> list = new ArrayList<>(arr.length);for (String s : arr) {if (!s.isBlank()) list.add(s.trim());}return list;}public static String asString(Object o) {return (o == null) ? null : String.valueOf(o);}public static Optional<BigDecimal> asDecimal(Object o) {try {if (o == null) return Optional.empty();if (o instanceof BigDecimal bd) return Optional.of(bd);if (o instanceof Number n) return Optional.of(new BigDecimal(n.toString()));if (o instanceof String s && !s.isBlank()) return Optional.of(new BigDecimal(s.trim()));} catch (Exception ignore) {}return Optional.empty();}public static Optional<Boolean> asBoolean(Object o) {if (o == null) return Optional.empty();if (o instanceof Boolean b) return Optional.of(b);if (o instanceof String s) {String x = s.trim().toLowerCase(Locale.ROOT);if ("true".equals(x) || "1".equals(x) || "yes".equals(x)) return Optional.of(true);if ("false".equals(x) || "0".equals(x) || "no".equals(x)) return Optional.of(false);}return Optional.empty();}public static Optional<LocalDate> asDate(Object o) {if (o == null) return Optional.empty();try {if (o instanceof LocalDate d) return Optional.of(d);if (o instanceof OffsetDateTime odt) return Optional.of(odt.toLocalDate());if (o instanceof String s && !s.isBlank()) {DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_DATE;return Optional.of(LocalDate.parse(s.trim(), f));}} catch (Exception ignore) {}return Optional.empty();}
}

MatchRequest.java

package per.mjn.web.dto;import jakarta.validation.constraints.NotNull;
import lombok.Data;
import per.mjn.common.vo.RuleDetailVO;
import java.util.Map;@Data
public class MatchRequest {@NotNullprivate RuleDetailVO rule;@NotNullprivate Map<String, Object> context;
}

MatchResponse.java

package per.mjn.web.dto;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class MatchResponse {private boolean hit;
}

MatchController.java

package per.mjn.web;import jakarta.validation.Valid;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import per.mjn.engine.RuleEngine;
import per.mjn.web.dto.MatchRequest;
import per.mjn.web.dto.MatchResponse;@RestController
@RequestMapping(path = "/api/rules", produces = MediaType.APPLICATION_JSON_VALUE)
public class MatchController {private final RuleEngine ruleEngine;public MatchController() {this.ruleEngine = new RuleEngine();}@PostMapping(path = "/match", consumes = MediaType.APPLICATION_JSON_VALUE)public MatchResponse match(@RequestBody @Valid MatchRequest req) {boolean hit = ruleEngine.matches(req.getRule(), req.getContext());return new MatchResponse(hit);}
}

RuleEngineApplication.java

package per.mjn;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RuleEngineApplication {public static void main(String[] args) {SpringApplication.run(RuleEngineApplication.class, args);}}

application.yml

server:port: 8080
spring:jackson:serialization:WRITE_DATES_AS_TIMESTAMPS: false

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.2</version><relativePath/></parent><groupId>per.mjn</groupId><artifactId>rule-engine-springboot</artifactId><version>0.0.1-SNAPSHOT</version><name>rule-engine-springboot</name><description>rule-engine-springboot</description><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Preprocessing Model in MPC 3 - 基于同态加密的协议 - Over Rings 环

参考论文&#xff1a;SoK: Multiparty Computation in the Preprocessing Model MPC (Secure Multi-Party Computation) 博士生入门资料。抄袭必究。 本系列教程将逐字解读参考论文(以下简称MPCiPPM)&#xff0c;在此过程中&#xff0c;将论文中涵盖的40篇参考文献进行梳理与讲…

uni-app 跨平台项目的 iOS 上架流程:多工具组合的高效协作方案

跨平台框架的兴起&#xff0c;让许多团队选择 uni-app 来开发移动应用。 一套代码多端运行&#xff0c;确实大大降低了研发成本&#xff0c;但当项目进入 iOS 上架阶段 时&#xff0c;很多团队依旧面临挑战&#xff1a;证书复杂、环境不统一、上传繁琐。 本文结合实战经验&…

掌握 Linux 文件权限:chown 命令深度解析与实践

在 Linux 系统的日常运维与开发工作里&#xff0c;文件权限管理是保障系统安全、规范文件访问的关键环节。其中&#xff0c;chown 命令作为修改文件所有者及关联组的核心工具&#xff0c;对精准把控文件权限起着重要作用。接下来&#xff0c;我们将全面拆解 chown 命令&#xf…

计算机算术7-浮点基础知识

1. 浮点表示其中b表示基底&#xff0c;e表示指数&#xff0c;s表示尾数&#xff0c;注意在s的表示过程中&#xff0c;有个隐藏1.同时还有个符号位从下面这个图可以看出&#xff0c;向上溢出和向下溢出的概念&#xff0c;overflow表示的是数的绝对值超过了最大的表示范围&#x…

设计模式8-命令模式

定义 Command Partern: 将一个请求封装成一个对象&#xff0c;从而让你使用不同的请求把客户端参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;可以提供命令的撤销和恢复功能。&#xff08;核心思想是将“动作”与“执行者”解耦&#xff09; 场景 GUI&#xff1a;…

数据结构(顺序表力扣刷题)

1.移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作&…

机器学习 - Kaggle项目实践(6)Dogs vs. Cats Redux: Kernels Edition 猫狗二分类

Dogs vs. Cats Redux: Kernels Edition | Kaggle 任务&#xff1a;给定猫狗图像数据集 进行二分类。 Cats or Dogs - using CNN with Transfer Learning | Kaggle&#xff08;参考&#xff09; Cats or Dogs | Kaggle &#xff08;我的kaggle&#xff09; 本文介绍了使用Re…

基础的汇编指令

目录 1、接上一个csdn特殊功能寄存器 1.1CPSR寄存器 1.2SPSR寄存器 1.3CPSR寄存器的高四位和第四位 ​编辑 2、汇编指令的分类 3、汇编指令的基本格式 4、数据搬移指令&#xff08;赋值指令&#xff09; 4.1指令码 4.2指令格式 4.3测试代码 4.5立即数 4.6ldr伪指令 …

Docker实战避坑指南:从入门到精通

摘要&#xff1a;文人结合自身微服务实践&#xff0c;系统梳理从安装适配、镜像拉取&#xff0c;到运行配置、构建优化、多容器编排、数据持久化、监控运维等 Docker 全流程高频踩坑点&#xff0c;给出可落地的解决方案&#xff0c;帮助读者快速规避同类问题并提升容器化效率。…

《Bishop PRML》10.1. Variational Inference(2)理解VAE

通过VAE与AE理解变分分布的变量 如何理解变分推断公式中,Z和X的含义是什么? 知乎 变分自编码器VAE的数学原理。 csdn 变分自编码器(VAE)的数学原理以及实现 Loss functions in Variational Autoencoders (VAEs) 一文解释 VAE+ELBO AE的编码和解码是确定性的。VAE的解码过程…

函数调用中的初始化与赋值——深入理解C++对象的生命周期

技术博客&#xff1a;函数调用中的初始化与赋值——深入理解C对象的生命周期引言在C编程中&#xff0c;理解函数调用过程中参数传递、对象创建和返回值处理的细节对于编写高效且无误的代码至关重要。本文将通过一个具体的例子来探讨函数调用时实参到形参的转换过程&#xff0c;…

矩阵微积分的链式法则(chain rule)

矩阵微积分的链式法则&#xff08;chain rule&#xff09;与标量情况一样&#xff0c;用于求复合函数的导数&#xff0c;但由于涉及矩阵和向量的求导&#xff0c;维度匹配和布局约定&#xff08;numerator-layout vs. denominator-layout&#xff09;必须格外小心。下面给出常见…

网络编程4-并发服务器、阻塞与非阻塞IO、信号驱动模型、IO多路复用..

一、并发服务器1、单循环服务器&#xff08;顺序处理&#xff09; 一次只能处理一个客户端连接&#xff0c;只有当前客户端断开连接后&#xff0c;才能接受新的客户端连接2、多进程/多线程并发服务器while(1) {connfd accept(listenfd);pid fork(); // 或 pthread_cr…

在 WSL2-NVIDIA-Workbench 中安装Anaconda、CUDA 13.0、cuDNN 9.12 及 PyTorch(含完整环境验证)

在 WSL-NVIDIA-Workbench&#xff08;NVIDIA AI Workbench & Ubuntu 22.04&#xff09;中 安装 Anaconda、CUDA 13.0、cuDNN 9.12 及 PyTorch 步骤也可参阅&#xff1a; 在WSL2-Ubuntu中安装Anaconda、CUDA13.0、cuDNN9.12及PyTorch&#xff08;含完整环境验证&#xf…

Shell编程核心入门:参数传递、运算符与流程控制全解析

Shell编程核心入门&#xff1a;参数传递、运算符与流程控制全解析 在Linux/Unix系统中&#xff0c;Shell作为命令解释器和脚本语言&#xff0c;是自动化运维、批量处理任务的核心工具。掌握Shell脚本的参数传递、运算符使用和流程控制&#xff0c;能让你从“手动执行命令”升级…

如何用 Kotlin 在 Android 手机开发一个应用程序获取网络时间

使用 NTP 协议获取网络时间在 build.gradle 文件中添加以下依赖&#xff1a;implementation commons-net:commons-net:3.6创建 NTP 时间获取工具类&#xff1a;import org.apache.commons.net.ntp.NTPUDPClient import org.apache.commons.net.ntp.TimeInfo import java.net.In…

python智慧交通数据分析可视化系统 车流实时检测分析 深度学习 车流量实时检测跟踪 轨迹跟踪 毕业设计✅

博主介绍&#xff1a;✌全网粉丝50W&#xff0c;前互联网大厂软件研发、集结硕博英豪成立软件开发工作室&#xff0c;专注于计算机相关专业项目实战6年之久&#xff0c;累计开发项目作品上万套。凭借丰富的经验与专业实力&#xff0c;已帮助成千上万的学生顺利毕业&#xff0c;…

计算机视觉第一课opencv(四)保姆级教学

目录 简介 一、轮廓检测 1.查找轮廓的API 2.代码分析 2.1.图像二值化处理 2.2轮廓检测 2.3轮廓绘制 2.4轮廓面积计算 2.5轮廓周长计算 2.6筛选特定面积的轮廓 2.7查找最大面积的轮廓 2.8绘制轮廓的外接圆 2.9绘制轮廓的外接矩形 二、轮廓的近似 三、模板匹配 简…

基于Vue2+elementUi实现树形 横向 合并 table不规则表格

1、实现效果 共N行&#xff0c;但是每一列对应的单元格列数固定&#xff0c;行数不固定2、实现方式说明&#xff1a;使用的是vue2 elementUI表格组件 js实现<template><div class"table-container" ><el-table height"100%" :span-metho…

深度学习在计算机视觉中的应用:对象检测

引言 对象检测是计算机视觉领域中的一项基础任务&#xff0c;目标是在图像或视频帧中识别和定位感兴趣的对象。随着深度学习技术的发展&#xff0c;对象检测的准确性和效率都有了显著提升。本文将详细介绍如何使用深度学习进行对象检测&#xff0c;并提供一个实践案例。 环境准…