Solidity数组全解析:从数据位置到ABI编码的实战避坑指南
先抛一个反直觉的结论Solidity 里的数组在函数之间传递时很多情况下并不是值在移动而是数据位置的引用在移动。我第一次写批量空投合约时函数需要接收两个数组——地址列表和金额列表结果一编译就报Data location must be memory or calldata当时完全懵了明明在 JavaScript 里数组想怎么传就怎么传怎么到了 Solidity 这里连参数声明都要被管后来才明白Solidity 数组与函数输入输出之间的这套规则本质上是 EVM 内存模型和 Gas 计费共同作用的结果。这篇文章会把数组在函数入口、函数出口、内部存储三个方向上的玩法讲透包括 storage/memory/calldata 到底怎么选、返回值怎么声明才能不被 ABI 坑、前端解析数组时为什么会出现莫名其妙的前缀、以及我在真实合约项目里踩过的各种编译器和调用层问题。无论你是刚学 Solidity 的新手还是写过几个合约但一直被数组细节折磨的进阶开发者这都能当一份实战排错手册用。1. 数组的三种国籍storage、memory、calldata 怎么选1.1 为什么 Solidity 不像 JavaScript 那样让数组自由飞JavaScript、Python 这种高级语言的数组是对象传参传的是引用内存管理交给运行时。Solidity 不行因为 EVM 的内存模型是极其朴素的存储数据的地方分成几种互不相通的区域读写成本完全不同。数组作为一种引用类型必须显式告诉编译器它活在哪个区域否则编译器不知道是该用SLOAD/SSTORE还是MLOAD/MSTORE也不知道一次赋值到底要复制多少个 32 字节的字。这三种数据位置里storage 是链上持久化存储读一次要SLOADgas 很贵写一次SSTORE更贵但数据能活到天荒地老。memory 是临时内存函数执行期间有效按字节计费比 storage 便宜一个数量级但函数一退出就没了。calldata 是外部调用传入的原始字节区域只读、不可修改读取成本最低因为它就是交易数据本身不需要额外复制。所以当你写function foo(uint256[] memory arr)时你是在告诉编译器我接受一份临时内存拷贝可以随便改但函数结束就丢。写function foo(uint256[] calldata arr)则是在说我直接读调用者原始数据快、省但别想在我这里对数组做文章。理解了这个底层动机后面很多细节就不是死记硬背而是能推理出来的了。1.2 数组参数默认用哪种位置这里有个入门必踩的报错很多新手写第一个合约时会写function sum(uint256[] arr) external pure returns (uint256) { uint256 total 0; for (uint256 i 0; i arr.length; i) { total arr[i]; } return total; }编译器立刻甩你一脸Data location must be memory or calldata for parameter in function, but none was given.这个报错不是没事找事而是 Solidity 0.5.0 之后强制要求所有引用类型参数必须显式声明数据位置。为什么因为如果不声明默认值在不同场景下不一样太容易出安全问题。想象一下一个数组参数被默认当作 storage 引用函数里改了一下链上数据就被篡改了这谁能接受。正确的做法是// 外部函数优先用 calldata省钱又安全 function sum(uint256[] calldata arr) external pure returns (uint256) { uint256 total 0; for (uint256 i 0; i arr.length; i) { total arr[i]; } return total; }internal 函数不能声明 calldata因为内部调用根本没有独立的调用数据区域。如果某个函数既要能被外部调用又要被内部模块调用参数一般选 memory 更稳妥内部调用时编译器会自动处理复制。这个内部调用没有 calldata的约束是很多人在拆分工具函数时踩坑的根源。1.3 三种数据位置互相转换的规则表数组在不同位置之间赋值并不是想转就转的规则不复杂但很硬性。我在项目里通常用下面这张表做快速判断赋值方向结果说明storage → memory逐元素复制成本高元素越多越贵storage → storage引用共享两个变量指向同一块存储互相影响memory → storage逐元素复制会写链上需付 SSTORE gasmemory → memory引用共享修改元素会互相可见calldata → memory逐元素复制手动复制后可在 memory 中修改calldata → calldata引用传递常用于切片传递零拷贝storage → calldata不支持直接赋给外部调用必须先经 memory 中转举个例子你从外部拿到一个 calldata 数组想存到状态变量里那么storedArr calldataArr会隐式触发逐元素拷贝。量小无所谓如果是个上万元素的数组这一下可能直接把 gas 干穿。所以我一般在写批量操作合约时会在入口处对数组长度做硬限制比如require(arr.length 500)防止有人恶意传超长数组烧你的合约。2. 函数入参数组传进来的各种写法和隐藏坑2.1 calldata 入参的真正优势省掉一次从调用数据到内存的复制external 函数如果把参数声明成 memory编译器在进入函数体之前会先把 calldata 里的原始字节按元素复制到内存中每个元素都要花 gas。对于只需要读取、不会改动的数组这个复制完全是浪费。改成 calldata 之后数组直接指向原始调用字节读取元素时按需访问gas 能省不少。我做过一个简单的对比测试一个 1000 元素的 uint256 数组求和memory 参数版本和 calldata 参数版本相比后者大约能省掉 10% 到 15% 的 gas元素越大、访问次数越多差距越明显。对高频调用的合约来说这个优化不是玄学是真金白银。当然calldata 数组也有限制不能 push、不能 pop、不能修改元素内容也不能把 calldata 数组直接赋给某个 storage 数组后通过这个 storage 引用改它。凡是需要修改数组内容的场景老老实实复制到 memory 或 storage 里再操作。2.2 calldata 是只读的想修改数组内容怎么办这是很多人的困惑点我需要在函数里对入参数组做点调整比如给每个金额加上手续费那 calldata 根本改不了怎么办答案很直接先复制到 memory。function applyFee(uint256[] calldata amounts, uint256 fee) external pure returns (uint256[] memory) { uint256[] memory result new uint256[](amounts.length); for (uint256 i 0; i amounts.length; i) { result[i] amounts[i] fee; } return result; }这里有个新手极其容易踩的坑memory 动态数组用new uint256[](length)创建之后长度就固定了你不能在 memory 数组上 push 新元素。Solidity 的push/pop只存在于 storage 数组上。所以当你不确定最终数组长度时常见做法是先在 storage 里建临时数组push 完再返回或者循环两遍——第一遍统计有效元素数量第二遍填值。这两种方案在 gas 上的取舍我会在后面章节细说。2.3 数组切片处理 calldata 入参被很多人忽略的利器如果你只需要数组中某一段连续元素Solidity 0.6.0 之后提供了切片语法arr[start:end]但限制是只能用于 calldata 数组而且切片结果仍然是 calldata不能赋值给 memory 变量后直接当独立数组用。function sumSlice(uint256[] calldata arr) external pure returns (uint256) { // 从第二个元素开始到第五个元素结束不含第五个 uint256[] calldata slice arr[1:5]; uint256 total 0; for (uint256 i 0; i slice.length; i) { total slice[i]; } return total; }切片的优点很实在零拷贝、零额外 gas、不改变原始数组。它本质上就是一个带偏移量和长度限制的视图。内部函数不能用 calldata 参数所以切片主要用于外部函数的入口处做初步过滤比如从签名数据里截取某一段或者把一个大数组按批次拆开处理。2.4 多维数组入参要注意维度顺序多维数组在 Solidity 里的写法容易让人绕晕。uint256[3][]和uint256[][3]是完全不同的东西前者是外层动态、内层定长 3后者是外层定长 3、内层动态。实际开发中遇到最多的是第一种比如批量转账时每个地址对应一组金额数据。function batchTransfer( address[] calldata recipients, uint256[][] calldata amounts ) external { // amounts[i] 是对应 recipients[i] 的一组金额 }前端调用时amounts传的是嵌套数组。但要注意ABI 对嵌套动态数组的编码是数组的数组每个内层数组都有独立的偏移量和长度前缀前端解析得到一个二维 JS 数组是很自然的可你要是直接拿 JSON-RPC 的原始返回值去对账看到一堆 16 进制偏移量会被绕晕。这个点我在后面专门讲。3. 函数返回值数组怎么出去ABI 在背后做了什么3.1 返回数组之前必须知道的复制成本外部函数的返回值如果是数组通常写成returns (uint256[] memory)。编译器在 return 时会把数组编码成 ABI 格式写入返回数据区编码过程不是免费的每个元素都要按 32 字节对齐收费。也就是说返回一个大型数组本身就在烧 gas调用方其实也省不了。内部函数之间可以返回 storage 引用吗可以但仅限 internal 函数而且这种引用不能跨外部调用边界。如果你写function getList() external view returns (uint256[] storage)编译器直接报错。因为外部世界根本没有办法接收一个指向合约存储的指针ABI 里不存在这种类型。正确做法是返回 memory 数组让编译器把 storage 内容复制出来再编码。这里有个实战建议如果返回数组只是为了给前端展示尽量加分页逻辑比如function getList(uint256 offset, uint256 limit) external view returns (uint256[] memory)。一次返回 10000 个元素gas 成本高、前端解析也卡不是笔划算买卖。3.2 public 数组的自动 getter 陷阱状态变量声明成public后会自动生成 getter这一点很多人知道。但数组的 public getter 有坑它不像 mapping 一样接受 key 参数而是把整个数组一次性返回。比如contract Demo { uint256[] public numbers; }外部调用numbers()得到的不是某个元素而是整个数组。你如果想通过 getter 拿特定索引的元素Solidity 不会为你生成带索引的 getter你得自己写function getNumber(uint256 index) external view returns (uint256)。这个设计导致一个实际风险如果数组很长任何人在链下调用numbers()都要让节点执行一次完整复制和编码节点压力倒还好但如果你在合约里也用this.numbers()这种外部方式调用就会白白支付巨额 gas。合约内访问 public 数组直接写numbers就行相当于操作 storage 引用别多此一举绕到外部。3.3 返回结构体数组的组合玩法数组元素不只有基础类型结构体数组是 DeFi 类合约里非常常见的返回类型。比如流动性池的用户持仓列表struct Position { address user; uint256 amount; uint256 pendingReward; } Position[] private positions; function getPositions() external view returns (Position[] memory) { return positions; }这段代码的 gas 成本取决于positions的长度和每个结构体字段的多少。结构体数组返回时会按字段顺序展开编码前端用 ethers 拿到的是一个对象数组每个对象对应一个结构体实例。字段顺序、字段类型必须和 ABI 完全一致一旦合约升级改了一个字段名字前端不会报错但值会错位。我踩过一次很痛的坑结构体里加了一个新字段后老前端解析出来的amount变成了新字段的值整整一个下午在对账最后才发现是 ABI 缓存没刷新。后来我养成了习惯只要合约接口变了强制前端同步更新合约 ABI 文件并重启本地缓存服务。3.4 返回动态数组和固定数组的编码差异固定长度数组和动态长度数组在 ABI 编码时不一样。动态数组会带一个长度前缀固定数组不会。比如uint256[3]返回时就是 3 个 uint256 依次排列而uint256[]返回时会先写一个长度 3再写 3 个元素。这个差异平时不会暴露可一旦你用低级工具比如直接发 eth_call 看原始返回数据排查问题时就会发现动态数组的十六进制返回串前面多了一个0x...0000000000000000000000000000000000000000000000000000000000000003之类的长度段。别把它当成数据否则解析出来的第一个值永远是数组长度。4. storage 数组的操作细节push、pop、删除与长度管理4.1 动态 storage 数组的 push/pop 与长度关系storage 动态数组是唯一支持push和pop的数组类型因为它的长度存在链上可以随交易改变。push(x)把元素追加到末尾pop()移除末尾元素length实时更新。这里有个大家都在用的技巧push 之后要知道新元素下标应该在 push 之前记录arr.length。uint256[] private list; function addItem(uint256 value) external returns (uint256 index) { index list.length; list.push(value); }0.6.0 之前的 push 语法和现在的有些差别老代码迁移到新版本编译器时经常报错。常见的报错是TypeError: Wrong argument count for struct constructor或者 push 参数不对原因多半是旧版数组的 push 用法已经被改掉了。新版里arr.push()不带参数会添加一个零值元素arr.push(value)才是带值追加。4.2 delete 不缩短长度真正删除元素的两种姿势很多新手以为delete arr[i]会把第 i 个元素删掉数组长度变小。这是误解。delete arr[i]只是把第 i 个元素重置为默认值长度不变。真正的删除并缩短长度只有两条路一是pop从尾部删二是替换后 pop。如果数组顺序不重要最省 gas 的删除方式是function removeBySwap(uint256 index) external { require(index list.length, out of bounds); list[index] list[list.length - 1]; list.pop(); }这招本质上是用最后一个元素覆盖要删除的位置再删掉尾部。代价是数组顺序会变原本最后一个元素跑到被删元素的位置上了。如果顺序必须保留就只能用循环把后面的元素逐个前移再 pop 掉最后的空位。循环前移在元素多时很贵所以实际项目里很多团队宁可维护一个已删除标记位也不做真正的搬移。4.3 删除整个数组的正确打开方式delete list可以把整个 storage 数组长度归零里面所有元素重置为默认值。这个操作会触发 gas 退款适合需要清空全部数据的场景。但要注意如果数组很长清零过程本身要遍历所有槽位写入零值gas 消耗可能极大退款抵不上花费。我在一个抽奖合约里就遇到过这个矛盾活动结束后要清空几万个参与者地址直接delete participants结果那笔交易把区块 gas 上限都快顶满了险些失败。后来改成分页清理每次只清空一部分多次交易完成。这种设计在数据量上千万时几乎是必须的任何指望一次交易搞定全量删除的想法都会在 gas 面前低头。5. 踩坑实录从编译器报错到前端数据错位的完整排查链路5.1 报错 Data location must be memory or calldata 的现场还原这个错我隔三差五就会看到一次尤其是在同事交过来的新代码里。典型场景是有人写了这样一个内部工具函数function _deduplicate(uint256[] arr) internal pure returns (uint256[] memory) { // 去重逻辑 }看起来没毛病但编译就是报Data location must be memory or calldata for parameter in function。排查链路很简单先把函数声明改成uint256[] memory arr编译通过但如果你把它改成uint256[] calldata arr编译器又会报另一个错——因为 internal 函数没有 calldata。最后的正确做法是统一用 memory并且在调用方传参时注意如果传进来的是 storage 数组编译器会帮你复制到 memory如果传进来的是 calldata 数组编译器也会先复制。也就是说这里多出来的 gas 是内部函数机制决定的不完全是写法问题。这个报错的价值在于强迫你思考函数的服务范围如果它只被外部调用用 calldata 最省如果它既要外部调用又要内部调用memory 才是通解。5.2 前端拿到的返回数组里为何会出现长度前缀项目上线前联调前端同学过来说返回的数组怎么第一个数字是 5我明明要的是 5 个转账记录不是这个数字。我第一反应是合约返回错了翻代码发现合约返回类型是uint256[] memory怎么看都没毛病。后来查了半天发现前端没用 ethers 的合约方法而是直接对 JSON-RPC 返回的data字段做了ethers.AbiCoder.defaultAbiCoder().decode([uint256[]], data)这本身没错可她在前面多解了一次。问题本质是动态数组在 ABI 编码时第一个 32 字节是长度后面才是元素。如果解析时多了一层剥壳长度就会被当成元素。排查链路最后固定为打开返回的十六进制串数一下前 64 个十六进制字符是不是长度然后一层层对齐类型。这个习惯后来帮我避免过至少三次类似事故。5.3 二维数组在 ethers.js 里到底长什么样多维数组在前端的解析结果不是一列数字而是嵌套数组。比如合约返回uint256[2][]ethers v6 解析出来是[ [100, 200], [300, 400] ]。如果你在 UI 表格里直接渲染这个数组可能出现一列nested array字样或者自动展开成多列结果完全取决于你用哪个组件。我踩过的一个具体坑是用 React 表格组件渲染二维数组时组件把内层数组当成了对象直接输出[object Object]。排查链路是先在浏览器控制台打印合约返回值确认前端拿到的是合法嵌套数组再检查表格组件的 column 定义发现缺少对数组字段的render函数。后面补了一个自定义 render把内层数组合并成字符串问题就解决了。这类问题跟 Solidity 本身没关系但联调时特别消磨时间提前约定好二维数组在前端表现为嵌套数组、每个内层元素是定长数组能省掉大量沟通成本。5.4 一个和数组长度有关的 off-by-one 事故还有一次合约里有一个循环要把calldata数组里的元素两两配对条件是i arr.length - 1。当时数组长度是 5我预期得到 4 组配对可实际只得到 3 组。排查半天发现遍历时用了i 2步进导致越过了最后一组元素。这事的教训不是数学问题而是 Solidity 数组的索引从 0 开始且length是元素个数不是最大索引。最大索引是length - 1遍历到length一定会越界访问数组末尾元素请一定是arr[arr.length - 1]。这个低级错误在高强度联调时特别容易复发所以我后来写了一个 require 断言工具函数专门检查索引边界避免线上合约被越界访问打爆。6. 写合约时数组相关的几条实战经验6.1 gas 优先的前提下怎么选择数组数据位置经过前面这些讲解选型逻辑其实已经很清晰了。外部函数的数组入参能 calldata 就 calldata这是性价比最高的选择需要修改入参内容时先复制到 memory需要持久化保存时赋值给 storage 状态变量但要提前评估元素复制的代价。内部函数之间传数组优先传 storage 引用可以让多个内部函数共享同一份存储而不用复制但如果内部函数只是读数据传 memory 或 calldata 转 memory 的代价有时候比传 storage 引用更可控因为 storage 引用在循环里反复访问时每次都是 SLOAD。一个经验参数如果数组超过几百个元素且内部函数只需要读一遍复制到 memory 后连续访问可能比每次 SLOAD 更划算。如果只需要访问几个分散的元素直接用 storage 引用更省。条件不同结论完全不同最好的方式是在测试网上实际对比两版 gas别凭空猜。6.2 批量操作场景里的数组长度上限和分页任何接收外部数组的函数都应该考虑恶意超长数组攻击。外部调用者可以传一个几百万元素的数组让你的 for 循环在函数内部消耗巨额 gas甚至直接让交易失败。这不是智能合约漏洞而是典型的 gas griefing 攻击。我通常在入口加这样的限制require(recipients.length 200, batch too large); require(recipients.length amounts.length, length mismatch);第二个 require 也值得强调两个数组长度不一致是批量操作的常见 bug 来源前端少传一个地址合约就会读取到越界或默认值。对账阶段发现金额对不上十个里有九个是这种问题。6.3 与前端协作时的类型对应关系约定后端合约和前端联调时数组相关的类型映射必须提前写在接口文档里。Solidity 的uint256[]在 ethers v5 里返回BigNumber[]v6 里返回bigint[]如果前端直接把这些大整数当普通 Number 用超过Number.MAX_SAFE_INTEGER就会丢精度。金额类数据必须做好格式转换前端展示时要除以 10 的 decimals 次方。嵌套数组、结构体数组、动态数组的编码差异这些内容我也建议写进接口文档。前端同学不是每个都了解 ABI你只需要告诉他Solidity 返回动态数组会带长度前缀解析时用现成库方法别手动剥壳就行了。图省事的方式是封装一个统一的 ABI 解析工具类所有合约返回的数组都从那个工具类走这样即使 ABI 格式变化也只需要改一处。6.4 最后分享一个排查数组问题的小技巧如果在合约里怀疑某个数组的某个索引值不对最快的方式不是加 console.log因为链上没有终端。我一般会在临时函数里把数组内容转换成 keccak256 哈希后返回前端拿到哈希后和本地重新计算的哈希比对。如果哈希一致说明数据传递完全没问题问题出在前端展示如果哈希不一致再逐步缩小范围看看是入参错误还是存储错误。这套方法不需要改合约的对外接口只要临时加一个 view 函数排查完删掉即可比漫无目的地打印所有元素高效得多。数组在 Solidity 里的坑说到底大多不是数组本身的问题而是数据位置、ABI 编码、gas 计费这些底层机制叠加出来的结果。把 storage、memory、calldata 三种位置彻底分清把动态数组编码时的长度前缀刻在脑子里再在项目里多踩几次编译器和前端的报错后面遇到类似问题基本都能一眼定位。希望这篇文章能帮你少走一点我已经走过的弯路。

相关新闻

PHP学生成长档案管理系统源码解析:部署、功能与避坑指南

PHP学生成长档案管理系统源码解析:部署、功能与避坑指南

简介:这份《学生成长档案管理系统》源代码源自大专院校版,以成长档案袋为核心理念,帮助教师记录并跟踪学生在学科学习与综合能力上的点滴进步,是一种发展性评价的落地实现。资源包含完整的前端展示与后端处理逻辑,覆盖…

2026/10/15 3:09:34 阅读更多 →
Zustand实现computed的几种方式与踩坑指南

Zustand实现computed的几种方式与踩坑指南

从 Vue 切到 React 18 Zustand 的团队,十有八九会在一个月内问出同一个问题:Zustand 里怎么实现 computed?在 Vue 里写惯了computed(() > ...),到了 Zustand 这边发现根本没有这个内置概念,网上搜"在 Zustand…

2026/10/15 3:09:33 阅读更多 →
MySQL误操作恢复必会:Binlog Digger 4.8.0解析与回滚SQL实战

MySQL误操作恢复必会:Binlog Digger 4.8.0解析与回滚SQL实战

简介:MySQL Binlog Digger 4.8.0 是面向 MySQL 运维与数据恢复人员的 Binlog 挖掘分析工具说明文档,帮助用户在误删、误改等场景下生成可执行的 redo/undo SQL。文档共 1 个 PDF 文件,压缩包约 60KB,内容覆盖工具的核心功能、版本…

2026/10/15 0:43:14 阅读更多 →

最新新闻

流量取证:从协议分层到线索建模的网络法证分析

流量取证:从协议分层到线索建模的网络法证分析

1. 这不是“抓包”那么简单:流量取证到底在解决什么问题“杂项题的基本解题思路——4、流量取证技术”,光看标题,很多人第一反应是:“哦,Wireshark打开,过滤http,找flag?”——这就像…

2026/10/16 4:02:12 阅读更多 →
LeetCode打卡Day3:哈希表、链表反转与栈匹配三类高频题深度拆解

LeetCode打卡Day3:哈希表、链表反转与栈匹配三类高频题深度拆解

Day3,打卡继续。今天这第7到第9题,我特意放在同一天做,不是随手翻到哪页刷哪页,而是按“字符串处理—链表操作—栈结构应用”这条线排的。三道题恰好覆盖了三类面试高频考点,题目本身不算难,但想在三十分钟…

2026/10/16 4:02:12 阅读更多 →
用WorkBuddy把散装资料变成可直接授课的教案和PPT:一条实战工作流

用WorkBuddy把散装资料变成可直接授课的教案和PPT:一条实战工作流

上周接到一门企业内训课,主题是《数据分析入门——数据清洗与可视化》,学员是 40 多名刚入职的非技术岗员工,课时只有 90 分钟。最让我头疼的不是讲课本身,而是开课前一天晚上,我盯着电脑里的"课程资料"文件…

2026/10/16 4:02:12 阅读更多 →
前沿技术与产品全覆盖:从业务需求出发的技术选型实操

前沿技术与产品全覆盖:从业务需求出发的技术选型实操

前两年我参与过一个行业解决方案的前期调研,那时候团队里流行一种做法:把“前沿技术与产品全覆盖”当成一场信息收集比赛。搜索引擎、技术社区、厂商白皮书……能看的都看,能记的都记,最后整理出一份上百页的技术清单,…

2026/10/16 4:02:12 阅读更多 →
MNN编译安装全攻略:从源码构建到移动端部署实战

MNN编译安装全攻略:从源码构建到移动端部署实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 4:02:12 阅读更多 →
内网离线安装Docker与docker-compose全流程及避坑指南

内网离线安装Docker与docker-compose全流程及避坑指南

简介:这份资源面向需要在无外网环境下部署容器服务的内网运维与开发人员,提供一套完整的离线安装方案,解决服务器无法访问公网、无法通过 yum 在线拉取 Docker 组件的痛点。压缩包共 22 个文件,约 120.91MB,以 20 个 r…

2026/10/16 4:01:12 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →