Solidity 运算符完全指南:类型提升、三元表达式、delete 与优先级详解

发布时间:2026/9/12 5:54:55

Solidity 运算符完全指南:类型提升、三元表达式、delete 与优先级详解 Solidity 运算符完全指南类型提升、三元表达式、delete 与优先级详解【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity导读本文以 Solidity 官方文档 docs/types/operators.rst 为主体系统讲解智能合约开发中最容易踩坑的运算符语义不同整数类型混合运算时的共同类型common type确定机制、字面量的**移动类型mobile type**规则、三元运算符的隐蔽溢出陷阱、复合赋值与自增自减的区别以及delete对值类型/引用类型/映射/结构体的不同行为。文章同时结合当前仓库的 libsolidity/ast/Types.cpp 源码与 docs/types/operator-precedence-table.rst 完整优先级表帮助你写出类型安全、行为可预期且不会因溢出意外回滚的合约代码。一、混合类型运算共同类型Common Type确定机制算术运算与位运算并不要求两个操作数类型完全相同。例如可以计算y x z其中x是uint8、z是uint32。此时编译器必须确定两件事运算在哪种类型下执行——这直接关系到溢出行为运算结果的类型。Solidity 采用如下三步机制确定这也是文档中定义的规则如果右操作数的类型可以隐式转换为左操作数的类型则使用左操作数的类型否则如果左操作数的类型可以隐式转换为右操作数的类型则使用右操作数的类型否则该运算不被允许编译报错。这段规则的源码实现位于 Types.cpp 的Type::commonTypeType const* Type::commonType(Type const* _a, Type const* _b) { if (!_a || !_b) return nullptr; else if (_a-mobileType() _b-isImplicitlyConvertibleTo(*_a-mobileType())) return _a-mobileType(); else if (_b-mobileType() _a-isImplicitlyConvertibleTo(*_b-mobileType())) return _b-mobileType(); else return nullptr; }可以看到判断的核心是isImplicitlyConvertibleTo隐式可转换性。结果类型与运算执行类型相同唯一的例外是比较运算符——比较运算的结果永远是bool无论参与比较的操作数是什么类型。二、字面量与移动类型Mobile Type当其中一个操作数是数字字面量时它不会直接以字面量身份参与运算而是先被转换为它的移动类型mobile type——即能容纳该值的最小类型。这里有一个关键细节相同位宽下无符号类型被认为比有符号类型“更小”优先选择。例如字面量255的移动类型是uint8而-1的移动类型是int8因为uint8无法容纳负数。如果两个操作数都是字面量运算以“实际上无限精度”的方式求值——表达式会被计算到不损失任何精度的程度直到结果与某个非字面量类型一起使用时才发生截断。移动类型的源码实现在 Types.cppType const* RationalNumberType::mobileType() const { if (!isFractional()) return integerType(); // 整数 - 最小的可容纳整型 else return fixedPointType(); // 小数 - 定点类型 }其中integerType()会根据值的正负与大小选择有符号/无符号的最小型见 Types.cpp。三、特殊运算符**、、的结果类型绝大多数二元运算符的结果类型等于运算执行时的共同类型但有三个例外**幂运算左移右移这三个运算符始终使用左操作数的类型进行运算并作为结果类型。源码依据见 Types.cpp 的IntegerType::binaryOperatorResultif (TokenTraits::isShiftOp(_operator)) { // Shifts are not symmetric with respect to the type if (isValidShiftAndAmountType(_operator, *_other)) return this; // 移位运算结果类型取左操作数 ... } else if (Token::Exp _operator) { ... return this; // 幂运算结果类型取左操作数底数 }同时该实现还隐含了另一个重要约束移位操作的右操作数移位量必须是无符号类型用有符号类型作为移位量会产生编译错误幂运算的指数同样不允许是有符号类型也不允许是负数或小数。另外注意与算术运算不同移位运算永远不做溢出检查结果总是被截断以匹配左操作数的类型。例如uint8(255) 8的结果是uint8类型高位移出的位会被丢弃详见 value-types.rst 中关于 Shifts 的说明。四、三元运算符表达式语义与两个经典陷阱三元运算符的形式为expression ? trueExpression : falseExpression它根据主表达式expression的求值结果只对其后两个表达式中的一个进行求值。其类型规则有两个要点三元运算符的结果没有有理数rational类型即使三个操作数都是有理数字面量也是如此结果类型由两个分支操作数按照与普通二元运算相同的方式先转换为移动类型确定。这带来了两个非常经典的“反直觉”后果是面试和审计中常见考点陷阱一255 (true ? 1 : 0)会因溢出而回滚uint8 x 255; uint8 y x (true ? 1 : 0); // 回滚原因是(true ? 1 : 0)的结果类型是uint8字面量1和0的移动类型都是uint8这迫使整个加法也在uint8下执行而256超出了uint8的取值范围[0, 255]触发算术溢出检查交易回滚。如果写成255 1两个字面量会以无限精度求值得256再根据上下文例如赋值给uint16决定是否合法。陷阱二1.5 1.5合法1.5 (true ? 1.5 : 2.5)不合法1.5 1.5是两个有理数字面量的运算以无限精度求值结果3.0是合法的有理数表达式只有最终值才被关注1.5 (true ? 1.5 : 2.5)中括号内的三元表达式结果不是有理数类型而是一个定点数fixed point类型需要一个“分数有理数转整数”的转换而这一转换目前是被禁止的因此编译失败。五、复合赋值与自增/自减运算符如果a是一个LValue左值即可被赋值的变量或表达式以下运算符可以作为简写使用运算符等价形式a ea a ea - ea a - ea * ea a * ea / ea a / ea % ea a % ea | ea a \| ea ea a ea ^ ea a ^ ea ea a ea ea a e自增自减有两组语义返回值的时机不同后缀形式a、a--等价于a 1/a - 1但表达式本身的值为a变化前的值前缀形式a、--a对a的影响相同但返回的是a变化后的值。例如uint x 5; uint y x; // y 5, x 6 uint z x; // z 7, x 7六、delete运算符按类型区分的重置语义delete a将a重置为该类型的初始值。理解delete的关键是它本质上是一次对a的赋值——即把一个新的对象存入a。这一点在a是引用类型变量时尤为重要delete a只会重置a本身而不会重置它之前所引用的对象。6.1 各类类型的行为整数等值类型delete a等价于a 0动态数组赋值为长度为 0 的动态数组静态数组赋值为长度不变、所有元素均重置为初始值的数组delete a[x]删除数组索引x处的元素其他元素和数组长度保持不变。这意味着数组中间会留下一个“空洞”如果频繁删除元素mapping 通常是更好的选择结构体将所有成员重置。但映射成员不会被重置映射的键是任意的、通常不可枚举delete会递归重置所有非映射成员遇到映射成员则跳过映射delete a对映射本身无效但delete a[x]可以删除键x对应的值。6.2 官方示例别名与引用语义文档给出了一个完整的可运行示例operators.rst 原文// SPDX-License-Identifier: GPL-3.0 pragma solidity 0.4.0 0.9.0; contract DeleteExample { uint data; uint[] dataArray; function f() public { uint x data; delete x; // 将 x 置为 0不影响 data delete data; // 将 data 置为 0不影响 x uint[] storage y dataArray; delete dataArray; // 将 dataArray.length 置为 0但由于 uint[] 是复杂对象 // y 作为该 storage 对象的别名同样受到影响 // 反过来delete y 是无效的因为指向 storage 对象的局部变量 // 只能由已存在的 storage 对象赋值而来。 assert(y.length 0); } }这个例子精妙地展示了两点值类型uint的delete只影响被删除的变量本身别名互不影响引用类型uint[] storage的delete修改的是底层 storage 对象因此所有指向该对象的别名如y都会观察到变化——这正是“delete真的表现为一次赋值”的含义。同时delete y不合法因为局部变量指向 storage 对象的引用只能从已存在的 storage 对象赋值得到。七、运算符优先级完整表Solidity 运算符按优先级从高到低共分 15 级内容完整取自 docs/types/operator-precedence-table.rst高优先级先求值优先级说明运算符1后缀自增、自减,--new 表达式new typename数组下标array[index]成员访问object.member函数式调用func(args...)括号(statement)2前缀自增、自减,--一元负号-一元运算delete逻辑非!按位取反~3幂运算**4乘、除、取模*,/,%5加、减,-6按位移位,7按位与8按位异或^9按位或\|10不等式比较,,,11等式比较,!12逻辑与13逻辑或\|\|14三元运算符conditional ? if-true : if-false赋值运算符,\|,^,,,,,-,*,/,%15逗号运算符,几个需要注意的要点赋值运算符包括复合赋值与三元运算符同处第 14 级低于所有算术、位、逻辑与比较运算因此a b c中先算b c再赋值delete是一元运算符优先级第 2 级远高于它常常搭配使用的下标运算第 1 级中的[]但下标是后缀操作先于delete应用因此delete a[x]的语义是先定位a[x]再删除比较运算符第 10 级优先级高于等式运算符第 11 级因此a b c d按(a b) (c d)解析。八、结合源码的实战要点溢出、移位与取模为了让运算结果符合预期以下语义细节值得结合整型文档与 Types.cpp 源码一起掌握默认所有算术都是 checked带检查模式运算结果超出类型范围会通过失败断言回滚可用unchecked { ... }切换为 wrapping回绕模式。因此混合类型运算的“共同类型”选择直接决定了是否会溢出回滚——这也是文档强调类型确定机制“在溢出情况下很重要”的原因。移位不做溢出检查结果总是被截断以匹配左操作数类型源码中isValidShiftAndAmountType只校验类型合法性不校验范围。除零与取模零无法被unchecked豁免它们触发Panic错误。唯一会发生溢出的除法是type(int).min / (-1)。整数除法向零取整int256(-5) / int256(2) int256(-2)。取模结果的符号与左操作数一致int256(-5) % int256(2) int256(-1)且恒有a % n -(-a % n)对负数a。幂运算**的指数必须为无符号类型源码 Types.cpp 对 signed 指数直接报错结果类型等于底数类型0**0在 EVM 中被定义为1。结语运算符是 Solidity 语法中表面简单、实则细节密集的部分。混合类型运算的“共同类型”机制、字面量的移动类型转换、三元运算符的非有理数结果、delete的引用别名语义以及严格的优先级顺序共同决定了合约的计算行为。建议在实际编写合约时显式声明类型避免依赖隐式转换在涉及边界值的场景主动用type(X).min/type(X).max校验范围对复杂 storage 结构的清理优先考虑 mapping 或自定义的pop式结构避免delete在数组中留下空洞。如需进一步了解整型的全部运算符语义与 unchecked 模式细节可继续阅读 docs/types/value-types.rst 与仓库中的类型系统实现 libsolidity/ast/Types.cpp。【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/12 5:54:55

Java面向对象编程:类与对象核心概念详解

1. Java面向对象编程基础:类与对象的核心概念在Java编程语言中,类和对象是面向对象编程(OOP)的基石。对于初学者来说,理解这两个概念是掌握Java的关键第一步。类可以看作是一个蓝图或模板,它定义了对象的属性和行为;而…

2026/9/12 5:54:55

蜜罐技术解析与Hfish开源蜜罐实战部署

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

2026/9/12 6:34:59

SpringBoot+Vue3全栈开发获奖作家管理系统实践

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

2026/9/12 6:34:59

Prompt as Code:工业级提示工程实践指南

我无法根据当前输入生成符合要求的博文。 原因如下: 项目标题 "awesome-gpt-image-2" 缺乏明确的技术指向、功能定义或领域背景,仅是一个命名风格(类似开源项目命名惯例),但未说明其本质是工具库&#xff…

2026/9/12 6:34:59

跨境电商精细化运营:供应链、库存与物流的核心策略

1. 跨境电商运营的现状与困境最近和几位跨境电商老友聚会,大家不约而同地提到一个现象:现在做跨境电商,流量获取已经不再是最大的难题,真正让卖家们拉开差距的,反而是那些看似不起眼的"底层运营能力"。这让我…

2026/9/12 6:29:59

仿抖音Android大作业:基于ExoPlayer和RecyclerView的短视频列表实现

简介:面向安卓课程设计与期末大作业的仿抖音APP完整项目包,包含源代码、答辩PPT、演示视频与部署说明,适合需要快速完成高质量移动端作业的初学者参考。项目功能覆盖视频播放、点赞评论等常见模块,界面美观、操作简单,…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码