本教程使用的开发环境是一款在线编译器——ChainIDE,具体的使用方法在之前的文章当中已经有讲解过,有需要的同学可以自行查看。
序言
变量值是一个程序最基础的部分,不管是各类的运算符,还是逻辑,都是由一个个值支撑的。
Solidity是一种静态程序语言,也就是说它的每一个变量都需要对它指定类型(或者能推断出的类型)。在程序当中有可能会用到的是以下几种类型:布尔类型、整型、定长浮点型(不完全支持)、地址类型、常数类型。
作为一个经历过一些其他语言的编程者,我必须承认,在Solidity当中的变量这个环节是非常复杂的,智能合约是由逻辑+计算组成的,在计算当中的任何一个不安全或者是溢出都有可能会导致智能合约的崩溃。
在本章当中介绍的一些计算和运行方式仅作为教学使用,实际项目部署当中的计算往往需要使用已经经过市场校验和实践过的库, 比如Openzepplin的Safemath。
在结尾会有一个对所有类型的计算以及例程的总结,有需要的可以直接跳至底部。
布尔类型
布尔类型的关键词是bool,其值可以为true或者false,这个类型与其他语言基本相同。
有两个运算符需要注意,分别是||和&&。在这里,它们遵循短路原则,意思就是如果在||时第一个变量值为true,就不会去看第二个变量了。同样的,如果&&的时候第一个变量为false,也不会去看第二个变量。
Tips:布尔类型在实际的运算与比较当中有可能是某个表达式的结果,如果这个表达式涉及到对某个变量的修改,建议放在布尔类型运算符外。
整型
Solidity支持有符号和无符号整数(uint/int),对于不同长度的整数需要设置长度(可以从8~256,比如128位无符号整数是uint128),uint/int是uint256/int256的别称。
整型支持的运算符与其他的语言类似,包括比较运算符、位运算符、算数运算符。在对整数进行除法运算时,会进行截断操作,小数点之后的东西会被舍去。
Tips:在对有符号整数进行位运算时需要小心,有可能会导致负号消失,或者在运行时出现其他问题,最好不要对有符号整数进行左移或者右移运算。
地址类型
地址类型是以太坊的一个特有类型,它是一个160位二进制的数,不同于Bitcoin的UTXO模型,以太坊交易是以其特定的账户模型,每个账户都有其对应的地址。
地址类型有几个常用的成员函数可以调用,首先是balance可以调用地址的当前余额,transfer和send可以向当前地址发送代币。
在合约当中,this关键字对应的是该合约的地址,address(this)可以返回对应的值。
bytes类型
bytes2 bytes_example = 0x2353;
bytes类型又被成为定长字节数组,但是其实它在定义时并不像其他数组那样,它在定义时就是一个固定的长度的储存空间,长度可以从1~32,定义时使用bytes2这样表示2个字节长度的值,bytes1的别称是byte。
当后面不带数字时,bytes单写则是表示不定长数组,就属于引用变量类型了,有时这个写法会带来一些不必要的内存使用,这个后面我们会讨论。
bytes类型的变量在初始化之后就不可以进行更改了,如果要对它进行修改,需要通过遍历的方式赋给一个新的变量。
bytes变量也有一个length的成员函数,可以输出这个变量的长度是多少,便于遍历的执行。
枚举类型
enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
ActionChoices choice;
枚举变量与其他语言基本是类似的,通过预设置枚举变量的值,在后续赋值时选择在枚举类内的值进行赋值。每个值对应一个数字,默认是从0开始逐个计数的。
Tips:在配置预设枚举类型时后面是不需要分号的。
常量
就我个人经历而言,Solidity对各种常量的处理方式好像是独树一帜的,Solidity内的常量有以下几类:数值常量、地址常量、字符串常量、十六进制常量。
1.数值常量
uint d_int = 5/2+4/2; //返回值为9/2,编译无法通过
数值类的常量运算跟我们之前说的又不太一样,数值类的运算不会截断,但是如果在运算结束后结果不符合前面变量类型的话,编译不会通过。
数值类的常数还可以使用科学计数法比如3e10这样的数字,但指数一定要是整数,因为不能出现无理数,同时还要注意的是这个数字的大小不能超过类型的长度限制。
2.地址常量
地址常量代表的是通过了地址校验和测试的十六进制字面常数,其实也就是我们之前在定义地址变量时赋值的那个值。
3.字符串常量
Solidity语言当中的字符串可以是'123'或者是"abc",对于这种类型的变量bytes类型和string类型可以互相转换。
字符串常量的长度是它所表示的字符串大小,后面不带有停止符。
4.十六进制常量
十六进制字面常数以关键字 hex 打头,后面紧跟着用单引号或双引号引起来的字符串(例如,hex"001122FF")。 字符串的内容必须是一个十六进制的字符串,它们的值将使用二进制表示。
示例代码
pragma solidity >=0.4.22 <0.6.0;
contract Variable {
//布尔变量演示
bool a_bool = true;
bool b_bool = false;
bool c_bool = a_bool != b_bool;
function get_c_bool() public view returns(bool)
{
return c_bool; // 返回值true
}
//整型变量演示
uint a_int = 5;
uint b_int = 2;
uint c_int = a_int / b_int;
function get_c_int() public view returns(uint)
{
return c_int+c_int; // 返回值4
}
//地址类型
address public account2 = 0x797206393eB6582ac86883fA623CB5A05021191D;
//返回当前合约地址
function get_contract_address() public view returns(address)
{
return address(this); //0xE0CfA8573cFe2c078039Df2462A05E2c19bb86A6
}
function get_contract_balance() public view returns(uint)
{
return address(this).balance;
}
//bytes类型
bytes2 bytes_example = 0x2353;
function get_bytes_length() public view returns(uint)
{
return uint(bytes_example.length);
}
//枚举类型
enum Color { Red, Yellow, Blue, SitStill }
Color constant car_color = Color.Blue;
function getChoice() public pure returns (Color) {
return car_color; // 返回值2
}
//常量计算演示
function get_d_int() public pure returns(uint)
{
uint d_int = 5/2+5/2+3.14e10+0x12; //2.5+2.5+31400000000+18
return d_int; // 返回值为31400000023
}
}
参考资料
常量不截断与变量截断的演示https://blog.csdn.net/weixin_43343144/article/details/88135232
拼接字符串
https://my.oschina.net/u/3794778/blog/1800631
solidity中文文档
https://solidity-cn.readthedocs.io/zh/develop/index.html