类型
Solidity是一种静态类型语言,所以每个变量都需要在编译时指定变量的类型。
“undefined”或“null”值的概念在Solidity中是不存在的
值类型
变量始终按值来传递。当这些变量被用作函数参数或者用在赋值语句中时,总会进行值拷贝。
布尔类型
bool
:取值为字面常数值true
和false
运算符:
!
(逻辑非)&&
(逻辑与)||
(逻辑或)==
(等于)!=
(不等于)
运算符||
和&&
都遵循短路规则
整型
int
:表示有符号的不同位数的整型变量。支持int8
到int256
,以8位为步长增长。int
等价于int256
uint
:表示无符号的不同位数的整型变量。支持uint8
到uint256
,以8位为步长增长。uint
等价于uint256
运算符:
- 比较运算符:
<=
,<
,==
,!=
,>=
,>
(返回布尔值) - 位运算符:
&
,|
,^
(异或),~
(位取反) - 移位运算符:
<<
(左移位) ,>>
(右移位) - 算术运算符:
+
,-
, 一元运算负-
(仅针对有符号整型),*
,/
,%
(取余或叫模运算) ,**
(幂)
对于整形x
,可以使用type(x).min和type(x).max去获取这个类型的最小值和最大值。
Solidity的整数是有取值范围。在0.8.0开始,算术运算有两个计算模式:一个是截断模式或不检查模式,一个是检查模式。默认情况下,都会进行溢出检查,如果出现结果落在取值范围之外,就会调用失败异常进行回退。可通过unchecked{...}
切换到不检查模式
比较运算
比较整型的值
位运算
位运算在数字的二进制补码表示上执行。
移位
移位操作的结果具有左操作数的类型,同时会截断结果以匹配类型。右操作数必须是无符号类型。
- 不管
x
正还是负,x << y
相当于x * 2 ** y
。 - 如果
x
为正数,x >> y
相当于x / 2 ** y
- 如果
x
为负数,x >> y
相当于(x + 1) / 2**y - 1
在版本0.5,0
之前,对于负 x
的右移 x >> y
相当于 x / 2 ** y
,即右移使用向上舍入而不是向下舍入
加法、减法、乘法运算
加法、减法和乘法与我们现实中使用相同。
在0.8.0
版本中加入溢出检查,默认情况下,算术运算都会进行溢出检查,但也可以通过unchecked{...}
来禁用检查,此时会返回截断后的结果;
在0.8.0
之前,是使用OpenZepplin SafeMath 库进行溢出的检查功能
表达式-x
相当于(x的类型(0)-x)。-x
只能应用在有符号型的整数上。
如果int x = type(int).min
,那么-x
将不在正数取值的范围内。这意味着这个检测unchecked{assert(-x==x)}
是可以通过的。如果是checked
模式,则会触发异常。具体详细理解,可以看一下补码的概念。
除法运算
除法运算结果的类型始终是其中一个操作数的类型,整数除法总是产生整数。在Solidity中,小数会取零。这意味着int256(-7)/int256(2) == int256(-2)
在智能合约中,字面常量上进行除法会保留精度(保留小数位)
除以0会发生Panic错误,而且不可以通过unchecked{...}
禁用掉
表达式type(int)min / -1
是仅有的整除会发生向上溢出的情况。在算术检查模式下,这会触发一个失败异常 ,在截断模式下,表达式的值将是type(int).min
模运算(取余)
模运算a%n
是在操作数a
的除以n
之后产生余数r
,其中q = int(a/n)
和r = a - (n*q)
。这意味着模运算结果与左操作数的符号相同。对于负数的a:a % n == -(a % n)
对0取模会发生错误Panic错误,该检查不能通过unchecked {...}
。
幂运算
幂运算仅适用于无符号类型。结果的类型总是基数的类型。请注意类型足够大以能够容纳幂运算的结果,要么发生潜在的assert异常或者使用截断模式
在checked
模式下,幂运算仅会为小基数使用相对便宜的exp
操作码。例如x**3
的表达式,可能x*x*x
也许会更便宜。在任何情况下,都建议进行Gas消耗测试和使用优化器
注意 0**0
在EVM中定义为 1
定长浮点型
Solidity还没有完全支持定长浮点型。可以定义声明定长浮点型的变量,但不能给它们赋值或把它们赋值给