Solidity学习(一)

01/08 13:12
阅读数 42

1.Solidity基础

友情提示:每一句话都非常重要,每一个点都是细节。再者本教程适合有一定编程基础的小伙伴快速入门
基本语法,整数溢出以及异常处理,字节数组,动态字节数组,字符串,字符串与字节数组的相互转换,帮助大家快速入门Solidity

这里直接给一段代码

pragma solidity ^0.4.16;

contract Helloworld {
    string Myname = "张三";
    function getName() public view returns(string) {
        return  Myname;
    }
    function setName(string newname) public {
        Myname = newname;
    }
     function pureTest(string _name) public pure returns (string) {
        return _name;
    }
}

这里使用的编辑器是remix网页编辑器:点击进入remix编辑器

下面我们对这段代码进行分析

在java中,已经有很多的小我们大致了解,所以我们学习solidity只需要学习它与其他语言不同的地方

  1. 第一行的prama,是solidity的编译控制指令,那我们这行代码的意思是,源文件不允许被0.4.16以下,以及大于等于0.5.0版本的编译器所编译,简单来说,允许的范围就是左闭右开

    0.4.16<=编译器版本<0.5.0

    在此区间的编译器版本是可以编译的。

  2. contract关键字,相当于java中的class,定义一个合约

  3. view关键字,这个是Solidity特有的关键字,因为solidity最终是用在合约上,所以会有相关的功能,而view就是这些功能的其中一个,view只能用来修饰方法,而被修饰的方法不能修改状态变量,也就是在java中的类的属性,在这里这个状态变量就是Myname,在这里我们可以看到getName()方法并没有修改Myname的值

  4. 运行这个代码,我们先调用getName函数,结果如下Redmix代码运行结果这张图片显示运行结果,运行成功
    油费1
    这张图片显示油费消耗,记住这个数字

  5. 运行setName()方法,这个方法需要传入一个参数,我们在这里传入"李四",点击运行,之后再运行getName()重新获取值,结果如下
    在这里插入图片描述
    在这里插入图片描述
    但是我们发现油费改变了,这说明了什么?


  6. 当我们继续点击getName()运行多次的时候,油费依旧不变,而当我们再次运行setName()方法的时候油费又会改变。

  7. 这说明了被view修饰的方法不会消耗油费,因为它不需要改变状态变量,所以view关键字还有节约油费的作用

  8. pure关键字,被这个关键字修饰的方法不允许访问状态变量,所以也不需要花费油费。

  9. bool,&& ,||,用法与java中完全一致,在这里不过多解释。

  10. uint关键字,代表非负整型,默认是uint256,256是指256个比特位,

8bit=1byte

  1. solidity中也支持方法重载
  2. 位运算符:由于solidity是用来部署合约,所以对内存要求很高,为了节约内存,位运算符显得相当重要

&:按位与,同时为1,得到1,有一个及以上为0,就是0
|:按位或,同时为0,得到0,有一个及以上为1,就是1
~:取反,0变成1,1变成0(只需要一串数字就可以)
^:按位异或,相同为0,不相同为1
<<:左移
.>>:右移




将上面的符号全部测试一遍,这里不给出结果,有兴趣的可以自己去运行一下


pragma solidity ^0.4.16;
   
   contract BoolTest {
       uint8 a = 4;
       uint8 b = 2;
       
       function plus() public view returns(uint8){
           return a + b;
       }
       function minus() public view returns(uint8){
           return a - b;
       }
       function multiply() public view returns(uint8){
           return a * b;
       }
       function divide() public view returns(uint8){
           return a / b;
       }
       function power() public view returns(uint8){
           return a ** b;
       }
       
       function test1() public view returns(uint8){
           return a&b;
       }
       function test2() public view returns(uint8){
           return a|b;
       }
       function test3() public view returns(uint8){
           return ~b;
       }
       function test4() public view returns(uint8){
           return a^b;
       }
       function test5() public view returns(uint8){
           return a<<1;
       }
        function test6() public view returns(uint8){
           return a>>1;
       }
   }

2.整数溢出以及异常处理

  1. 接下来我们要介绍非常危险的整数溢出问题,附上代码。
 function flow() public pure returns(uint8){
           uint8 mm = 255;
           return mm;
       }

我们知道。8个比特位的数据范围是0~255,所以这个方法会返回一个mm的值,是255,运行结果没问题。在这里插入图片描述
接下来我们修改一下代码,修改后的代码在下方

function flow() public pure returns(uint8){
           uint8 mm = 255;
           mm++;
           return mm;
       }

代码修改后,mm理应变成256,但是256已结超过了8个比特位的取值范围,所以会出现错误。运行结果:
在这里插入图片描述
可以看到,mm的值输出直接变成了0,为什么会有这种结果呢?

1 1 1 1 , 1 1 1 1

上面是我们的8个比特位,这个是255的二进制表示,当这个数加1的时候,最后一位加1,学过二进制的朋友都知道,依次从后往前满2进1,最后的结果是:

1, 0 0 0 0, 0 0 0 0

由于我们只能读取8个比特位,所以读取之后的值就是

0 0 0 0, 0 0 0 0

这个值就是0,所以m后8位读取变成了0。

为了验证我们的结论,我们再次修改代码:

 function flow() public pure returns(uint8){
           uint8 mm = 255;
           mm++;
           mm++;
           return mm;
       }

运行结果:
在这里插入图片描述
可以看到,当我们让mm在之前的基础上再加1之后,变成了

0 0 0 0, 0 0 0 1

所以mm的结果就是1,可以验证我们刚刚的结论是正确的。

  1. 我们再写一个函数,附上代码:
function erroTest() public pure returns(int){
            int a1 = 1;
            int a2 = 0;
            return a1/a2;
        }

注意观察上面的函数,很明显我们看到上面的函数发生了错误,因为0不能做除数,那我们编译这个代码是能通过的,但是当我们调用这个函数的时候就会看到以下字段
在这里插入图片描述
这就是发生了一个异常。

注意:solidity目前不支持小数类型

3.字节数组

我们还是先给一段代码

pragma solidity ^0.4.0;
 
 contract BytesArray {
     
     bytes1 public num1 = 0x7a;// 只有一个字节的数  二进制表示:0111 1010
     bytes2 public num2 = 0x7a68;// 有两个字节的数 二进制表示:0111 1010 0110 1000
     
     function getLength() public returns(uint256) {
          return num1.length;// length属性不可修改
     }
     
     function getLength2() public returns(uint256) {
          return num2.length;// length属性不可修改
     }
 }
  1. 字节数组虽然在存储上与int一致,但是不能直接进行加减乘除操作。但是可以进行数的比较(>,>=,==,<=,<),也可以进行位运算(&, |, ~, ^, <<, >>)。
  2. 当属性添加public后,会被默认生成一个获取该属性的get方法。
  3. 加上以下代码,验证上述说法,f分别求&, |, ~, ^, <<, >>位运算后的值,并返回。
 function and() public returns(bytes2 n1,bytes2 n2,bytes2 n3, bytes2 n4, bytes2 n5,bytes2 n6){
          return (num1&num2,num1|num2,~num1,num1^num2,num1<<1,num1>>1);
      }

得到结果:
在这里插入图片描述
结果正确。

4.动态字节数组

上代码:

 pragma solidity ^0.4.0;
 
 contract BytesArray {
     
     bytes public name = new bytes(2);
     
     function initName() public {
         name[0] = 0x7a;
         name[1] = 0x68;
     }
     
     function getLength() public returns(uint256){
         return name.length;
     }
     
     function changeLength() public {
         name.length = 5;
     }
 }
  1. 运行initName之后,再查看name属性的值:
    在这里插入图片描述
    结果没问题

  2. 运行getLength()方法查看bytes数组的长度:

在这里插入图片描述
长度是2,结果正确

  1. 运行changeLength()方法修改bytes数组的长度:
    在这里插入图片描述
    在这里插入图片描述
    长度变成了5


总结:动态字节数组能够修改数组的长度。

  1. name.push(0x99)向name动态字节数组中添加一个0x99的元素。

4.string类型

  1. string操作与java基本一致,string余额bytes之间可以强制转换,这一特性可以用来访问string中特定位置的值。
    代码测试
pragma solidity ^0.4.0;

contract StringTest {
    string public name = "zhangsan";
    
    function getLength() public returns(uint256){
        return bytes(name).length;
    }
    
    function changeName() public {
        bytes(name)[0] = 'L';
    }
    
    function getCName() public returns(bytes1){
        return bytes(name)[0];
    }
}
  1. 获取name:
    在这里插入图片描述
  2. 获取长度为8个字节:
    在这里插入图片描述
  3. 调用getCName()获取第一个字母:
    在这里插入图片描述
    6.调用changeName修改第一个字母之后再获取name:
    在这里插入图片描述


展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部