当前位置: 首页 > article >正文

JavaScript系列(51)--解释器实现详解

JavaScript解释器实现详解 🎯

今天,让我们深入探讨JavaScript解释器的实现。解释器是一个将源代码直接转换为结果的程序,通过理解其工作原理,我们可以更好地理解JavaScript的执行过程。

解释器基础概念 🌟

💡 小知识:解释器通常包括词法分析、语法分析、AST(抽象语法树)生成和解释执行等阶段。每个阶段都有其特定的任务和挑战。

词法分析器实现 📊

// 1. Token类型定义
const TokenType = {// 关键字LET: 'LET',CONST: 'CONST',FUNCTION: 'FUNCTION',RETURN: 'RETURN',IF: 'IF',ELSE: 'ELSE',WHILE: 'WHILE',// 标识符和字面量IDENTIFIER: 'IDENTIFIER',NUMBER: 'NUMBER',STRING: 'STRING',BOOLEAN: 'BOOLEAN',// 运算符PLUS: 'PLUS',MINUS: 'MINUS',MULTIPLY: 'MULTIPLY',DIVIDE: 'DIVIDE',ASSIGN: 'ASSIGN',EQUALS: 'EQUALS',// 分隔符LEFT_PAREN: 'LEFT_PAREN',RIGHT_PAREN: 'RIGHT_PAREN',LEFT_BRACE: 'LEFT_BRACE',RIGHT_BRACE: 'RIGHT_BRACE',SEMICOLON: 'SEMICOLON',COMMA: 'COMMA',// 其他EOF: 'EOF'
};// 2. 词法分析器
class Lexer {constructor(source) {this.source = source;this.tokens = [];this.start = 0;this.current = 0;this.line = 1;this.keywords = new Map([['let', TokenType.LET],['const', TokenType.CONST],['function', TokenType.FUNCTION],['return', TokenType.RETURN],['if', TokenType.IF],['else', TokenType.ELSE],['while', TokenType.WHILE],['true', TokenType.BOOLEAN],['false', TokenType.BOOLEAN]]);}scanTokens() {while (!this.isAtEnd()) {this.start = this.current;this.scanToken();}this.tokens.push({type: TokenType.EOF,lexeme: '',line: this.line});return this.tokens;}scanToken() {const c = this.advance();switch (c) {// 单字符tokencase '(': this.addToken(TokenType.LEFT_PAREN); break;case ')': this.addToken(TokenType.RIGHT_PAREN); break;case '{': this.addToken(TokenType.LEFT_BRACE); break;case '}': this.addToken(TokenType.RIGHT_BRACE); break;case ';': this.addToken(TokenType.SEMICOLON); break;case ',': this.addToken(TokenType.COMMA); break;// 运算符case '+': this.addToken(TokenType.PLUS); break;case '-': this.addToken(TokenType.MINUS); break;case '*': this.addToken(TokenType.MULTIPLY); break;case '/':if (this.match('/')) {// 单行注释while (this.peek() !== '\n' && !this.isAtEnd()) {this.advance();}} else {this.addToken(TokenType.DIVIDE);}break;case '=':this.addToken(this.match('=') ? TokenType.EQUALS : TokenType.ASSIGN);break;// 忽略空白字符case ' ':case '\r':case '\t':break;case '\n':this.line++;break;// 字符串case '"': this.string(); break;default:if (this.isDigit(c)) {this.number();} else if (this.isAlpha(c)) {this.identifier();} else {throw new Error(`Unexpected character: ${c} at line ${this.line}`);}break;}}// 辅助方法isAtEnd() {return this.current >= this.source.length;}advance() {return this.source.charAt(this.current++);}peek() {if (this.isAtEnd()) return '\0';return this.source.charAt(this.current);}match(expected) {if (this.isAtEnd()) return false;if (this.source.charAt(this.current) !== expected) return false;this.current++;return true;}isDigit(c) {return c >= '0' && c <= '9';}isAlpha(c) {return (c >= 'a' && c <= 'z') ||(c >= 'A' && c <= 'Z') ||c === '_';}isAlphaNumeric(c) {return this.isAlpha(c) || this.isDigit(c);}addToken(type, literal = null) {const text = this.source.substring(this.start, this.current);this.tokens.push({type,lexeme: text,literal,line: this.line});}string() {while (this.peek() !== '"' && !this.isAtEnd()) {if (this.peek() === '\n') this.line++;this.advance();}if (this.isAtEnd()) {throw new Error(`Unterminated string at line ${this.line}`);}// 消费结束引号this.advance();// 获取字符串值const value = this.source.substring(this.start + 1,this.current - 1);this.addToken(TokenType.STRING, value);}number() {while (this.isDigit(this.peek())) {this.advance();}// 处理小数if (this.peek() === '.' && this.isDigit(this.peekNext())) {this.advance();while (this.isDigit(this.peek())) {this.advance();}}const value = parseFloat(this.source.substring(this.start, this.current));this.addToken(TokenType.NUMBER, value);}identifier() {while (this.isAlphaNumeric(this.peek())) {this.advance();}const text = this.source.substring(this.start, this.current);const type = this.keywords.get(text) || TokenType.IDENTIFIER;this.addToken(type);}
}

语法分析器实现 🚀

// 1. AST节点类型
class ASTNode {constructor(type) {this.type = type;}
}// 2. 表达式节点
class BinaryExpr extends ASTNode {constructor(left, operator, right) {super('BinaryExpr');this.left = left;this.operator = operator;this.right = right;}accept(visitor) {return visitor.visitBinaryExpr(this);}
}class UnaryExpr extends ASTNode {constructor(operator, right) {super('UnaryExpr');this.operator = operator;this.right = right;}accept(visitor) {return visitor.visitUnaryExpr(this);}
}class LiteralExpr extends ASTNode {constructor(value) {super('LiteralExpr');this.value = value;}accept(visitor) {return visitor.visitLiteralExpr(this);}
}class VariableExpr extends ASTNode {constructor(name) {super('VariableExpr');this.name = name;}accept(visitor) {return visitor.visitVariableExpr(this);}
}// 3. 语句节点
class VariableStmt extends ASTNode {constructor(name, initializer) {super('VariableStmt');this.name = name;this.initializer = initializer;}accept(visitor) {return visitor.visitVariableStmt(this);}
}class ExpressionStmt extends ASTNode {constructor(expression) {super('ExpressionStmt');this.expression = expression;}accept(visitor) {return visitor.visitExpressionStmt(this);}
}// 4. 语法分析器
class Parser {constructor(tokens) {this.tokens = tokens;this.current = 0;}parse() {const statements = [];while (!this.isAtEnd()) {statements.push(this.statement());}return statements;}statement() {if (this.match(TokenType.LET, TokenType.CONST)) {return this.variableDeclaration();}return this.expressionStatement();}variableDeclaration() {const name = this.consume(TokenType.IDENTIFIER,"Expect variable name.");let initializer = null;if (this.match(TokenType.ASSIGN)) {initializer = this.expression();}this.consume(TokenType.SEMICOLON,"Expect ';' after variable declaration.");return new VariableStmt(name, initializer);}expressionStatement() {const expr = this.expression();this.consume(TokenType.SEMICOLON,"Expect ';' after expression.");return new ExpressionStmt(expr);}expression() {return this.equality();}equality() {let expr = this.term();while (this.match(TokenType.EQUALS)) {const operator = this.previous();const right = this.term();expr = new BinaryExpr(expr, operator, right);}return expr;}term() {let expr = this.factor();while (this.match(TokenType.PLUS, TokenType.MINUS)) {const operator = this.previous();const right = this.factor();expr = new BinaryExpr(expr, operator, right);}return expr;}factor() {let expr = this.unary();while (this.match(TokenType.MULTIPLY, TokenType.DIVIDE)) {const operator = this.previous();const right = this.unary();expr = new BinaryExpr(expr, operator, right);}return expr;}unary() {if (this.match(TokenType.MINUS)) {const operator = this.previous();const right = this.unary();return new UnaryExpr(operator, right);}return this.primary();}primary() {if (this.match(TokenType.NUMBER, TokenType.STRING, TokenType.BOOLEAN)) {return new LiteralExpr(this.previous().literal);}if (this.match(TokenType.IDENTIFIER)) {return new VariableExpr(this.previous());}if (this.match(TokenType.LEFT_PAREN)) {const expr = this.expression();this.consume(TokenType.RIGHT_PAREN,"Expect ')' after expression.");return expr;}throw this.error(this.peek(), "Expect expression.");}// 辅助方法match(...types) {for (const type of types) {if (this.check(type)) {this.advance();return true;}}return false;}check(type) {if (this.isAtEnd()) return false;return this.peek().type === type;}advance() {if (!this.isAtEnd()) this.current++;return this.previous();}isAtEnd() {return this.peek().type === TokenType.EOF;}peek() {return this.tokens[this.current];}previous() {return this.tokens[this.current - 1];}consume(type, message) {if (this.check(type)) return this.advance();throw this.error(this.peek(), message);}error(token, message) {return new Error(`[line ${token.line}] Error at '${token.lexeme}': ${message}`);}
}

解释器实现 💻

// 1. 执行环境
class Environment {constructor(enclosing = null) {this.values = new Map();this.enclosing = enclosing;}define(name, value) {this.values.set(name, value);}get(name) {if (this.values.has(name)) {return this.values.get(name);}if (this.enclosing) {return this.enclosing.get(name);}throw new Error(`Undefined variable '${name}'.`);}assign(name, value) {if (this.values.has(name)) {this.values.set(name, value);return;}if (this.enclosing) {this.enclosing.assign(name, value);return;}throw new Error(`Undefined variable '${name}'.`);}
}// 2. 解释器
class Interpreter {constructor() {this.environment = new Environment();}interpret(statements) {try {for (const statement of statements) {this.execute(statement);}} catch (error) {console.error('Runtime Error:', error);}}execute(stmt) {return stmt.accept(this);}evaluate(expr) {return expr.accept(this);}// 访问表达式visitBinaryExpr(expr) {const left = this.evaluate(expr.left);const right = this.evaluate(expr.right);switch (expr.operator.type) {case TokenType.PLUS:return left + right;case TokenType.MINUS:return left - right;case TokenType.MULTIPLY:return left * right;case TokenType.DIVIDE:return left / right;case TokenType.EQUALS:return left === right;}}visitUnaryExpr(expr) {const right = this.evaluate(expr.right);switch (expr.operator.type) {case TokenType.MINUS:return -right;}}visitLiteralExpr(expr) {return expr.value;}visitVariableExpr(expr) {return this.environment.get(expr.name.lexeme);}// 访问语句visitVariableStmt(stmt) {let value = null;if (stmt.initializer) {value = this.evaluate(stmt.initializer);}this.environment.define(stmt.name.lexeme, value);}visitExpressionStmt(stmt) {return this.evaluate(stmt.expression);}
}

性能优化技巧 ⚡

// 1. AST优化器
class ASTOptimizer {optimize(ast) {return this.visitNode(ast);}visitNode(node) {switch (node.type) {case 'BinaryExpr':return this.optimizeBinaryExpr(node);case 'UnaryExpr':return this.optimizeUnaryExpr(node);case 'LiteralExpr':return node;default:return node;}}optimizeBinaryExpr(node) {const left = this.visitNode(node.left);const right = this.visitNode(node.right);// 常量折叠if (left.type === 'LiteralExpr' && right.type === 'LiteralExpr') {const result = this.evaluateConstExpr(left.value,node.operator.type,right.value);return new LiteralExpr(result);}return new BinaryExpr(left, node.operator, right);}evaluateConstExpr(left, operator, right) {switch (operator) {case TokenType.PLUS: return left + right;case TokenType.MINUS: return left - right;case TokenType.MULTIPLY: return left * right;case TokenType.DIVIDE: return left / right;default: return null;}}
}// 2. 缓存优化
class InterpreterCache {constructor() {this.expressionResults = new Map();}get(expr) {return this.expressionResults.get(this.getExprKey(expr));}set(expr, result) {this.expressionResults.set(this.getExprKey(expr), result);}getExprKey(expr) {return JSON.stringify({type: expr.type,value: expr.value,operator: expr.operator?.type});}clear() {this.expressionResults.clear();}
}// 3. 执行优化
class OptimizedInterpreter extends Interpreter {constructor() {super();this.cache = new InterpreterCache();this.optimizer = new ASTOptimizer();}interpret(statements) {// 优化ASTconst optimizedStatements = statements.map(stmt => this.optimizer.optimize(stmt));// 执行优化后的语句super.interpret(optimizedStatements);}evaluate(expr) {// 检查缓存const cached = this.cache.get(expr);if (cached !== undefined) {return cached;}const result = super.evaluate(expr);this.cache.set(expr, result);return result;}
}

最佳实践建议 💡

  1. 错误处理和恢复
// 1. 错误处理器
class ErrorHandler {constructor() {this.errors = [];}report(line, where, message) {const error = `[line ${line}] Error ${where}: ${message}`;this.errors.push(error);console.error(error);}hasErrors() {return this.errors.length > 0;}clearErrors() {this.errors = [];}
}// 2. 错误恢复策略
class ErrorRecovery {static synchronize(parser) {parser.advance();while (!parser.isAtEnd()) {if (parser.previous().type === TokenType.SEMICOLON) return;switch (parser.peek().type) {case TokenType.FUNCTION:case TokenType.LET:case TokenType.CONST:case TokenType.IF:case TokenType.WHILE:case TokenType.RETURN:return;}parser.advance();}}
}// 3. 运行时错误处理
class RuntimeError extends Error {constructor(token, message) {super(message);this.token = token;}
}

结语 📝

JavaScript解释器的实现是一个复杂但有趣的主题。通过本文,我们学习了:

  1. 解释器的基本架构和工作原理
  2. 词法分析和语法分析的实现
  3. AST的生成和优化
  4. 解释执行过程
  5. 性能优化和错误处理

💡 学习建议:在实现解释器时,要注意模块化设计和错误处理。合理使用优化策略,可以显著提升解释器性能。同时,良好的错误提示对于开发者体验至关重要。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

JavaScript系列(51)--解释器实现详解

JavaScript解释器实现详解 &#x1f3af; 今天&#xff0c;让我们深入探讨JavaScript解释器的实现。解释器是一个将源代码直接转换为结果的程序&#xff0c;通过理解其工作原理&#xff0c;我们可以更好地理解JavaScript的执行过程。 解释器基础概念 &#x1f31f; &#x1f…...

浅析DDOS攻击及防御策略

DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一种通过大量计算机或网络僵尸主机对目标服务器发起大量无效或高流量请求&#xff0c;耗尽其资源&#xff0c;从而导致服务中断的网络攻击方式。这种攻击方式利用了分布式系统的特性&#xff0c;使攻击规模更大、影响范围更广…...

深度学习 Pytorch 神经网络的学习

本节将从梯度下降法向外拓展&#xff0c;介绍更常用的优化算法&#xff0c;实现神经网络的学习和迭代。在本节课结束将完整实现一个神经网络训练的全流程。 对于像神经网络这样的复杂模型&#xff0c;可能会有数百个 w w w的存在&#xff0c;同时如果我们使用的是像交叉熵这样…...

【回溯】目标和 字母大小全排列

文章目录 494. 目标和解题思路&#xff1a;回溯784. 字母大小写全排列解题思路&#xff1a;回溯 494. 目标和 494. 目标和 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式…...

Linux系统上安装与配置 MySQL( CentOS 7 )

目录 1. 下载并安装 MySQL 官方 Yum Repository 2. 启动 MySQL 并查看运行状态 3. 找到 root 用户的初始密码 4. 修改 root 用户密码 5. 设置允许远程登录 6. 在云服务器配置 MySQL 端口 7. 关闭防火墙 8. 解决密码错误的问题 前言 在 Linux 服务器上安装并配置 MySQL …...

Miniconda 安装及使用

文章目录 前言1、Miniconda 简介2、Linux 环境说明2.1、安装2.2、配置2.3、常用命令2.4、常见问题及解决方案 前言 在 Python 中&#xff0c;“环境管理”是一个非常重要的概念&#xff0c;它主要是指对 Python 解释器及其相关依赖库进行管理和隔离&#xff0c;以确保开发环境…...

记录一次,PyQT的报错,多线程Udp失效,使用工具如netstat来检查端口使用情况。

1.问题 报错Exception in thread Thread-1: Traceback (most recent call last): File "threading.py", line 932, in _bootstrap_inner File "threading.py", line 870, in run File "main.py", line 456, in udp_recv IndexError: list…...

kamailio-ACC_JSON模块详解【后端语言go】

要确认 ACC_JSON 模块是否已经成功将计费信息推送到消息队列&#xff08;MQueue&#xff09;&#xff0c;以及如何从队列中取值&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 确认 ACC_JSON 已推送到队列 1.1 配置 ACC_JSON 确保 ACC_JSON 模块已正确配置并启用。以下…...

群晖NAS安卓Calibre 个人图书馆

docker 下载镜像johngong/calibre-web&#xff0c;安装之 我是本地的/docker/xxx/metadata目录 映射到 /usr/local/calibre-web/app/cps/metadata_provider CALIBREDB_OTHER_OPTION 删除 CALIBRE_SERVER_USER calibre_server_user 缺省用户名口令 admin admin123 另外有个N…...

android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色

安卓自定义DatePicker选中日期颜色 背景&#xff1a;解决方案&#xff1a;方案一&#xff1a;方案二&#xff1a;实践效果&#xff1a; 背景&#xff1a; 最近在尝试用原生安卓实现仿element-ui表单校验功能&#xff0c;其中的的选择日期涉及到安卓DatePicker组件的使用&#…...

pytorch实现基于Word2Vec的词嵌入

PyTorch 实现 Word2Vec(Skip-gram 模型) 的完整代码,使用 中文语料 进行训练,包括数据预处理、模型定义、训练和测试。 1. 主要特点 支持中文数据,基于 jieba 进行分词 使用 Skip-gram 进行训练,适用于小数据集 支持负采样,提升训练效率 使用 cosine similarity 计算相…...

彩色控制台,自动换行...学习个新概念:流操控器![more cpp--11]

孩子们&#xff0c;我回来了。先看看今天我又学了什么CPP的没啥用新特性。彩色的控制台&#xff01; 还有很多的新花样&#xff01; 事情要从去年八月讲起&#xff0c;我那个时候在研究流函数&#xff0c;写了一些比较愚笨的代码。 为什么要研究这个呢&#xff1f;虽然我们的C…...

基于单片机的盲人智能水杯系统(论文+源码)

1 总体方案设计 本次基于单片机的盲人智能水杯设计&#xff0c;采用的是DS18B20实现杯中水温的检测&#xff0c;采用HX711及应力片实现杯中水里的检测&#xff0c;采用DS1302实现时钟计时功能&#xff0c;采用TTS语音模块实现语音播报的功能&#xff0c;并结合STC89C52单片机作…...

TensorFlow 示例摄氏度到华氏度的转换(一)

TensorFlow 实现神经网络模型来进行摄氏度到华氏度的转换&#xff0c;可以将其作为一个回归问题来处理。我们可以通过神经网络来拟合这个简单的转换公式。 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 …...

win10部署本地deepseek-r1,chatbox,deepseek联网(谷歌网页插件Page Assist)

win10部署本地deepseek-r1&#xff0c;chatbox&#xff0c;deepseek联网&#xff08;谷歌网页插件Page Assist&#xff09; 前言一、本地部署DeepSeek-r1step1 安装ollamastep2 下载deepseek-r1step2.1 找到模型deepseek-r1step2.2 cmd里粘贴 后按回车&#xff0c;进行下载 ste…...

【memgpt】letta 课程6: 多agent编排

Lab 6: Multi-Agent Orchestration 多代理协作 letta 是作为一个服务存在的,app通过restful api 通信 多智能体之间如何协调与沟通? 相互发送消息共享内存块,让代理同步到不同的服务的内存块...

Java 大视界 -- Java 大数据在自动驾驶中的数据处理与决策支持(68)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

【Linux】opencv在arm64上提示找不到libjasper-dev

解决opencv在arm64上提示找不到libjasper-dev的问题。 本文首发于❄慕雪的寒舍 问题说明 最近我在尝试编译opencv&#xff0c;安装依赖项libjasper1和libjasper-dev的时候就遇到了这个问题。在amd64平台上&#xff0c;我们可以通过下面的命令安装&#xff08;ubuntu18.04&…...

计算机组成原理——存储系统(一)

在人生的道路上&#xff0c;成功与失败交织成一幅丰富多彩的画卷。不论我们是面对胜利的喜悦&#xff0c;还是遭遇失败的痛苦&#xff0c;都不能放弃对梦想的追求。正是在这种追求中&#xff0c;我们不断地超越自我&#xff0c;不断地突破自己的极限。只有勇往直前&#xff0c;…...

【LLM-agent】(task4)搜索引擎Agent

note 新增工具&#xff1a;搜索引擎Agent 文章目录 note一、搜索引擎AgentReference 一、搜索引擎Agent import os from dotenv import load_dotenv# 加载环境变量 load_dotenv() # 初始化变量 base_url None chat_model None api_key None# 使用with语句打开文件&#xf…...

LabVIEW在电机自动化生产线中的实时数据采集与生产过程监控

在电机自动化生产线中&#xff0c;实时数据采集与生产过程监控是确保生产效率和产品质量的重要环节。LabVIEW作为一种强大的图形化编程平台&#xff0c;可以有效实现数据采集、实时监控和自动化控制。详细探讨如何利用LabVIEW实现这一目标&#xff0c;包括硬件选择、软件架构设…...

Baklib揭示内容中台与人工智能技术的创新协同效应

内容概要 在当今信息爆炸的时代&#xff0c;内容的高效生产与分发已成为各行业竞争的关键。内容中台与人工智能技术的结合&#xff0c;为企业提供了一种新颖的解决方案&#xff0c;使得内容创造的流程更加智能化和高效化。 内容中台作为信息流动的核心&#xff0c;能够集中管…...

18.Word:数据库培训课程❗【34】

目录 题目 NO1.2.3.4 NO5设置文档内容的格式与样式 NO6 NO7 NO8.9 NO10.11标签邮件合并 题目 NO1.2.3.4 FnF12&#xff1a;打开"Word素材.docx”文件,将其另存为"Word.docx”在考生文件夹下之后到任务9的所有操作均基于此文件&#xff1a;"Word.docx”…...

git多人协作

目录 一、项目克隆 二、 1、进入克隆仓库设置 2、协作处理 3、冲突处理 4、多人协作分支的推送拉取删除 1、分支推送&#xff08;2种&#xff09; 2、远程分支拉取&#xff08;2种&#xff09; 3、远程分支删除 一、项目克隆 git clone 画船听雨眠/test1 (自定义的名…...

团体程序设计天梯赛-练习集——L1-030 一帮一

前言 一道15分的题目&#xff0c;难度还可以&#xff0c;题目的内容都在幻想中&#xff0c;看题 L1-030 一帮一 “一帮一学习小组”是中小学中常见的学习组织方式&#xff0c;老师把学习成绩靠前的学生跟学习成绩靠后的学生排在一组。本题就请你编写程序帮助老师自动完成这个…...

什么是线性化PDF?

线性化PDF是一种特殊的PDF文件组织方式。 总体而言&#xff0c;PDF是一种极为优雅且设计精良的格式。PDF由大量PDF对象构成&#xff0c;这些对象用于创建页面。相关信息存储在一棵二叉树中&#xff0c;该二叉树同时记录文件中每个对象的位置。因此&#xff0c;打开文件时只需加…...

DRM系列四:初始化drm设备--drm_dev_init

本系列文章基于linux 5.15 一、drm_dev_alloc 用于分配并初始化一个新的 DRM 设备(即drm_device),初始化主要调用drm_dev_init函数 1.1drm_dev_init drm_device的初始化操作&#xff0c;但是并不会注册&#xff0c;函数定义在drivers/gpu/drm/drm_drv.c 其主要的作用&#…...

SpringMVC的参数处理

一、参数接收 1.使用servlet API接收参数 在方法参数中添加HttpServletRequest类型的参数&#xff0c;然后就可以像servlet的方法一样来接收参数 2.在方法中定义同名参数 如果url地址中的参数名与方法的参数名不一致时&#xff0c;可以使用RequestParam注解进行重新关联 url地…...

一觉醒来全球编码能力下降100000倍,新手小白的我决定科普C语言——函数

1. 函数的概念 数学中我们其实就⻅过函数的概念&#xff0c;⽐如&#xff1a;⼀次函数 y kx b &#xff0c;k和b都是常数&#xff0c;给⼀个任意的 x&#xff0c;就得到⼀个y值。其实在C语⾔也引⼊函数&#xff08;function&#xff09;的概念&#xff0c;有些翻译为&#xf…...

台账思维和GIS思维在资产管理中的不同模式

最近一些习惯用台账统计资产的网友聊天引发一些感想和大家分享一下&#xff1a;传统台账思维注重统计资产的数量及信息完整性&#xff0c;而GIS除了关心前两个指标外&#xff0c;更注重数据与现实世界是否能一一对应&#xff0c;即数据的现实准确性&#xff01; 例如&#xff1…...