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

发布时间:2026/11/13 19:14:40

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/11/13 19:14:40

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

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

2026/11/12 17:12:33

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

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

2026/11/13 19:11:49

大同高压电工证考什么千万别踩坑 初学者怎么避开报名陷阱

大同高压电工证考什么千万别踩坑 初学者怎么避开报名陷阱 不知道去哪报名怕被中介坑?大同高压电工证考什么,这是很多新手第一个想到的问题。别以为这只是个考试,背后藏着的坑多得让你防不胜防。我认识一个朋友,花了几千块报名,结果考试内容完全没讲过,…

2026/11/13 19:11:49

瑞金电工证考试时间报名入口与办理流程

电工证考试时间怎么算?学历不高怕报不上名?听真实经历怎么说 你是不是也担心自己学历不高,考电工证会不会被拒?其实很多人都有这个顾虑,特别是像我这样从技校毕业的,当时也纠结了好一阵子。后来我发现, 瑞金电工证考试时间…

2026/11/13 19:11:49

西峡考电工证在哪里,学历不高也能报名,全国通用!

西峡考电工证在哪里,学历不高也能报名,全国通用! 你是不是也担心自己学历不高,怕报不了电工证?其实不用慌,西峡考电工证在哪里,关键不是学历,而是你是否真正掌握了电工操作的技能和知识。电工证是全国通用的,考下来以后找工作、换岗、提升待遇都有用…

2026/11/13 19:11:49

电工证提交材料是什么 30天拿证怎么避坑

电工证提交材料是什么 30天拿证怎么避坑 怕考不过白交培训费?别急,先搞懂电工证提交材料是什么,再看多久拿证才靠谱! 作为一名在郑州做工程类工作的应届生,我太清楚了,电工证不是可有可无的“装饰品”,而是真正能让你在职场里“升职加薪”的硬通货…

2026/11/13 19:11:49

全南哪里考电工证好点内部消息告诉你怎么选

全南哪里考电工证好点内部消息告诉你怎么选 你是不是正在为找工作发愁?特种作业证成了你能不能上岗的关键,尤其是电工证,几乎是很多行业的入门门槛。而你在全南,听说 全南哪里考电工证好点…

2026/11/13 19:06:48

达濠年审电工证怎么考?电子证书怎么拿?找工作必看攻略

达濠年审电工证怎么考?电子证书怎么拿?找工作必看攻略 你是不是正为找不到电工相关的工作发愁?是不是看到招聘要求里写着“必须持有特种作业操作证”?别急,本文直接告诉你: 达濠年审电工证 怎么考、怎么拿电子证书,让你轻松应对岗位需求。…

2026/11/12 20:35:13

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/13 0:01:06

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了 你是不是也像我一样,第一次听说“高压电工证”这个名词,就感觉一头雾水?其实很多人都跟我一样,不知道去哪报名、怕被中介坑,结果花了冤枉钱还考不上。今天我就从一个在商丘培训过的学员角度,…

2026/11/13 0:01:06

黎里考电工证在哪里值不值得考

黎里考电工证在哪里值不值得考 之前考的证在外省能不能转过来?这是很多在外地工作、准备回老家发展的朋友最关心的问题。特别是在黎里地区,很多从事电力相关工作的朋友,都面临这样一个难题: 外省的电工证能否在本地使用?值不值得考?…

2026/11/13 0:01:06

毕节哪里考电工证 怎么报名学历不高也能上手

毕节哪里考电工证 怎么报名学历不高也能上手 你是不是也和我一样,学历不高,想着考个电工证,但又担心自己条件不够,怕报不上名?其实不然,只要符合条件,学历不高也能考电工证。今天就来聊聊【毕节哪里考电工证】这个问题,还有怎么报名,让你一步到位不…

2026/11/12 22:10:13

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/13 12:14:39

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

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

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

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