当前位置:   article > 正文

基于以太坊的智能合约开发Solidity(基础篇)_以太坊智能合约开发快速入门

以太坊智能合约开发快速入门

参考教程:基于以太坊的智能合约开发教程【Solidity】_哔哩哔哩_bilibili

1、第一个程序——Helloworld:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract HelloWorld
  5. {
  6.     //合约属性变量,也叫状态变量(定义方式:数据类型 变量名 = 数据)
  7.     string myName = "helloworld"; //在solidity中,用单引号包含字符串也是可以的
  8.     //合约中的方法(注意语法顺序,其中此处“view”代表方法只读,不会消耗燃料;“returns”后的是返回值类型)
  9.     function getName() public view returns(string)
  10.     {
  11.         return myName; //返回值类型要与returns声明的严格相同
  12.     }
  13.     //可以修改属性变量的值,但是会消耗燃料
  14.     function changeName(string _newName) public
  15.     {
  16.         myName = _newName;
  17.     }
  18.     //“pure”代表不能读取也不能改变状态变量
  19.     function pureName(string _name) public pure returns(string)
  20.     {
  21.         return _name;
  22.     }
  23.     /*
  24.     用constant、view、pure修饰function分别表示:
  25.     constant:只能读取不可改变状态变量(就是contract中定义的变量)
  26.     view:只能读取不可改变状态变量,和constant一样
  27.     pure:不能读取也不能改变状态变量
  28.     */
  29.    
  30. }

(1)程序编译完成后,需要在虚拟机上运行,将合约部署好后便可执行刚刚编写的函数。(注意,合约一旦部署,就会永久存在于区块链上,且不可篡改,不过可以销毁)

(2)执行完成后,可以得到以下交易信息,下图所示的就是生成的区块信息:

(3)代码相关:

①属性变量定义方式:数据类型 变量名 = 数据(变量命名规则和c语言相同)

②一般用双引号包含一串字符串,不过在solidity中,用单引号包含字符串也是可以的。

③Solidity值类型:(在Solidity中,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型,在调用函数时如果形参和实参类型不同将会报错

• 布尔类型(bool):可能的取值为字符常量值true或false

• 整型(int/uint):分别表示有符号和无符号的不同位数的整型变量,支持关键字uint8到 uint256(无符号,从8位到256位)以及int8到int256,以8位为步长递增

• 定长浮点型(fixed / ufixed):表示各种大小的有符号和无符号的定长浮点型,在关键字ufixedMxN和fixedMxN中,M表示该类型占用的位数,N表示可用的小数位数

• 地址(address):存储一个 20 字节的值(以太坊地址大小)

• 定长字节数组:关键字有 bytes1,bytes2,bytes3,...,bytes32

• 枚举(enum):一种用户可以定义类型的方法,与C语言类似,默认从0开始递增,一般用来模拟合约的状态

• 函数(function):一种表示函数的类型

④solidity函数的标准形式:

function functionName() {private|internal|external|public} [pure|constant|view|payable] [returns()]

在合约中定义函数要以function开头,后接函数名称,括号内则是传入函数中的参数(每一个参数的类型以及名称要依次写出,没有参数则不写),“returns”后接该函数返回值的类型(无返回值则可以不写returns)。

⑤用constant、view、pure修饰function分别表示:

    constant:只能读取、不可改变状态变量(就是contract中定义的变量)

    view:只能读取、不可改变状态变量,和constant一样,不消耗燃料

    pure:不能读取也不能改变状态变量,一个固定的输入只能有一个固定的输出

[1]以下情况被认为是修改状态:修改状态变量(函数体外部、合约内部创建的变量就是状态变量)、产生事件、创建其它合约、使用selfdestruct、通过调用发送以太币、调用任何没有标记为view或者pure的函数、使用低级调用、使用包含特定操作码的内联汇编。

[2]以下被认为是从状态中进行读取:读取状态变量、访问this.balance或者 <address>.balance、访问block,tx,msg中任意成员(除msg.sig和msg.data之外)、调用任何未标记为pure的函数、使用包含某些操作码的内联汇编。

⑥用external、public、internal、private修饰function分别表示:

    external:外部函数作为合约接口的一部分,意味着可以从其他合约和交易中调用,  一个外部函数f不能从内部调用(即f不起作用,但this.f()可以,这些后续都会详细介绍),当收到大量数据的时候,外部函数有时候会更有效率。

    public:public函数是合约接口的一部分,可以在内部或通过消息调用对于public状态变量,会自动生成一个getter函数

    internal:这些函数和状态变量只能是内部访问(即从当前合约内部或从它派生的合约访问),不使用this调用。

    private:private函数和状态变量仅在当前定义它们的合约中使用,并且不能被派生合约使用。

⑦solidity中函数可以递归调用。

⑧solidity可以使用import导入其它源文件:

[1]import "filename";  //从“filename”中导入所有的全局符号到当前全局作用域中

[2]import * as symbolName from "filename";  //创建一个新的全局符号symbolName,其成员均来自“filename”中的全局符号

[3]import {symbol1 as alias, symbol2} from "filename";  //创建新的全局符号alias和symbol2,分别从"filename"引用symbol1和symbol2

[4]import "filename" as symbolName;  //这条语句等同于import * as symbolName from "filename";

2、语法——逻辑运算:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract BoolTest
  5. {
  6.    
  7.     bool a;  //创建布尔类型变量时如不初始化,默认赋为false
  8.    
  9.     function geta() public returns(bool)
  10.     {
  11.         return a;
  12. }
  13. function getnota() public returns(bool)
  14.     {
  15.         return !a;  //a当前为false,经过非运算后会返回true
  16.     }
  17.     int c = 1;
  18.     int d = 2;
  19.    
  20.     //(这部分与c语言几乎完全相同,就不列举所有情形了)
  21.     function cdequal() public returns(bool)
  22.     {
  23.         return c==d;  //c与d当前不相等,c==d不成立,会返回false
  24.     }
  25.    
  26.     function cdequalAnd() public returns(bool)
  27.     {
  28.         return c==d && true;  //c==d返回false,false与true进行与运算,结果为false
  29.     }
  30.    
  31.     function cdequalOr() public returns(bool)
  32.     {
  33.         return c==d || true;  //c==d返回false,false与true进行或运算,结果为true
  34.     }
  35.    
  36.     function cdnotequalAnd() public returns(bool)
  37.     {
  38.         return c!=d && true;  //c与d当前不相等,c!=d成立,返回true,true与true进行或运算,结果为true
  39.     }
  40. }

3、语法——整型与算术运算:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract MathTest
  5. {
  6.     //加(a与b为传入方法中的参数,下同理)
  7.     function add(uint a,uint b) public returns(uint)
  8.     {
  9.         return a+b;
  10.     }
  11.     //减
  12.     function minus(uint a,uint b) public returns(uint)
  13.     {
  14.         return a-b;
  15.     }
  16.     //乘
  17.     function multiply(uint a,uint b) public returns(uint)
  18.     {
  19.         return a*b;
  20.     }
  21.     //除
  22.     function divide(uint a,uint b) public returns(uint)
  23.     {
  24.         return a/b;
  25.     }
  26.     //取余运算
  27.     function mod(uint a,uint b) public returns(uint)
  28.     {
  29.         return a%b;
  30.     }
  31.     //幂运算
  32.     function square(uint a,uint b) public returns(uint)
  33.     {
  34.         return a**b;
  35.     }
  36. }

4、语法——位运算:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract MathTest
  5. {
  6.     //uint8表示大小为8个位的无符号整型
  7.     uint8 a = 3;  //二进制表示为00000011
  8.     uint8 b = 4;  //二进制表示为00000100
  9.     //按位与(该部分和c语言也几乎完全相同)
  10.     function bitwiseAnd() public returns(uint8)
  11.     {
  12.         return a&b;
  13.     }
  14.     //按位或
  15.     function bitwiseOr() public returns(uint8)
  16.     {
  17.         return a|b;
  18.     }
  19.     //按位取反
  20.     function tilde() public returns(uint8)
  21.     {
  22.         return ~a;
  23.     }
  24.     //按位异或
  25.     function caret() public returns(uint8)
  26.     {
  27.         return a^b;
  28.     }
  29.     //左移(左移运算符后接左移的位数)
  30.     function leftShift() public returns(uint8)
  31.     {
  32.         return a<<1;
  33.     }
  34.     //右移(右移运算符后接右移的位数)
  35.     function rightShift() public returns(uint8)
  36.     {
  37.         return a>>1;
  38.     }
  39. }

(图源:https://blog.csdn.net/aiwaston/article/details/113665723

5、语法——复合运算:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract MathTest
  5. {
  6.     uint a = 1;
  7.     //该语法也和c语言基本完全相同
  8.     //输出a
  9. function add1() public returns(uint)
  10. {
  11.         return a++;  //执行完该语句后a的值会加1
  12.     }
  13.     //输出a+1
  14. function add2() public returns(uint)
  15. {
  16.         return ++a;  //执行该语句前a的值会加1,然后再执行该语句
  17.     }
  18.     //输出a
  19. function sub1() public returns(uint)
  20. {
  21.         return a--;  //执行完该语句后a的值会减1
  22.     }
  23.     //输出a-1
  24. function sub2() public returns(uint)
  25. {
  26.         return --a;  //执行该语句前a的值会减1,然后再执行该语句
  27.     }
  28. }

6、现象——整型溢出:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract MathTest
  5. {
  6.     //这部分也与c语言几乎完全相同
  7.     function flow() view public returns(uint8)
  8.     {
  9.         uint8 mm  = 255;  //二进制为11111111
  10.         mm++;
  11.         return mm;  //mm只有8位,但是对于mm,再加1会得到100000000,只能取前8位,于是返回0而不是256
  12.     }
  13.    
  14.     function flow2() view public returns(uint256)
  15.     {
  16.         uint8 mm  = 255;
  17.         mm++;
  18.         return mm;  //即使返回值声明有256位,但是在“mm++”这一步mm就被修改为0,所以返回的还是0
  19.     }
  20.    
  21.      function flow3() view public returns(uint)
  22.      {
  23.         uint mm  = 255;  //这次没对mm的位数进行限制,它可以装下100000000
  24.         mm++;
  25.         return mm;
  26.     }
  27.     function flow4() view public returns(uint8){
  28.         uint8 nn = 0;
  29.         nn--;
  30.         return nn;  //对00000000做减法,会先给“第九位”添1(要明确nn的位数),那么就会得到结果11111111,转换成十进制就是255(对于有符号数,就涉及到了补码的运算,同理,先转换成补码按此规律运算,再转换回十进制)
  31.     }
  32. }

7、现象——非法运算:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract MathTest
  5. {
  6.     function errorTest() view public returns(int)
  7.     {
  8.         int a = 2;
  9.         int b = 3;
  10.         return a/b;  //既然声明了返回值为整型,那么就不可能得到小数
  11.         //不过solidity允许整型运算的过程中存在小数,只是结果不能接纳小数,比如2/5-2/5
  12. //solidity会将表达式计算出结果后再按照一定的规则(比如整形溢出等)进行处理,比如2**99-2**99+1
  13.     }
  14.    
  15.     function errorTest2() view public returns(int)
  16.     {
  17.         int a = 2;
  18.         int b = 0;
  19.         return a/b;  //0不能做除数,这个方法甚至不能成功编译
  20.     }
  21.     function errorTest3() view public returns(int)
  22.     {
  23.         int a = -1;
  24.         int b = 0;
  25.         return b >> a;  //位移运算符不接受负数
  26.     }
  27.    
  28. }

8、语法——固定长度字节数组:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract ByteArray
  5. {
  6.     bytes1 public num1 = 0x7a;  //1个字节长度的变量
  7.    
  8.     bytes2 public num2 = 0x7a68;  //2个字节长度的变量
  9.    
  10.     bytes12 public num3 = 0x7a68656e676a69616e78756e;  //12个字节长度的变量
  11. }

(1)在solidity中,直接用public声明成员变量,编译部署后,会生成一个默认的get方法,通过该方法可以直接查看这个成员属性,而不需要通过自拟函数返回这个成员属性。

(2)字节数组同样支持位运算以及逻辑运算。

(3)固定长度字节数组不可以仅仅对某个字段进行更改(可以仅对某个字段进行读取,如下表所示),要么就直接对其整体重新赋值

名称

num3[0]

num3[1]

num3[2]

num3[3]

num3[4]

num3[5]

num3[6]

num3[7]

num3[8]

num3[9]

num3[10]

num3[11]

内容

0x7a

0x68

0x65

0x6e

0x67

0x6a

0x69

0x61

0x6e

0x78

0x75

0x6e

(4)定长字节数组的关键字有bytes1,bytes2,bytes3,...,bytes32。

(5)不管是定长数组还是动态长度数组,都不能越界访问,否则会报错。

9、语法——动态长度字节数组:

  1. //声明版本号(程序中的版本号要和编译器版本号一致)
  2. pragma solidity ^0.5.17;
  3. //合约
  4. contract DynamicByteArray
  5. {
  6.    
  7.     bytes public name = new bytes(2);  //为动态字节数组开辟2个字节的空间
  8.    
  9.     function initName() public
  10.     {
  11.         name[0] = 0x7a; //对动态长度字节数组进行初始化
  12.         name[1] = 0x68;
  13.     }
  14.    
  15.     function getLength() view public returns(uint)
  16.     {
  17.         return name.length;  //8个位(一个字节)为一个长度单位
  18.     }
  19.    
  20.     function changeName() public
  21.     {
  22.         name[0] = 0x88;  //可以对某一字段进行修改
  23.     }
  24.    
  25.     function changeLength() public
  26.     {
  27.         name.length = 5;  //可以修改数组的长度,不过修改的同时会将数组的内容全部置为0
  28.     }
  29.     function pushTest() public
  30.     {
  31.         name.push(0x99);  //可以在数组末尾追加字节元素,同时增加数组的长度
  32.     }
  33. }

(1)动态长度字节数组可以仅对某个字段进行更改

(2)可以通过修改动态长度数组的length属性修改动态长度数组的长度,不过修改的同时会将数组的内容全部置为0。

(3)动态长度数组有push方法,使用该方法可以在数组末尾追加指定的字节元素,同时增加数组的长度。

10、语法——mapping映射:

  1. pragma solidity ^0.5.17;
  2. contract mappingTest
  3. {
  4.     //个人认为这个有点像Python中的字典(可以理解为mapping(key => value) 字典名)
  5.     //一个钱包地址对应一个个人身份id
  6.     mapping(address => uint) idMapping;
  7.     //一个人的身份id地址对应一个人的姓名
  8.     mapping(uint => string) nameMapping;
  9.  
  10.     uint id = 0;
  11.     function register(string memory name) public //该函数模拟新账户绑定身份
  12.     {
  13.         address account = msg.sender;  //调用该函数的账户为需要绑定身份和生成id号的新账户
  14.         id++;  //这里的id号应该是随机生成,总之每个调用该函数的账户都应该获得不同的id号
  15.         //给账户分配一个id
  16.         idMapping[account] = id;
  17.         //再将个人id与个人姓名进行映射绑定
  18.         nameMapping[id] = name;        
  19.     }
  20.     //根据账户地址获取id
  21.     function getIdByAddress(address account) public view returns(uint)
  22.     {
  23.         return idMapping[account];
  24.     }
  25.     //根据id获取个人姓名
  26.     function getNameById(uint id) public view returns(string memory)
  27.     {
  28.         return nameMapping[id];
  29. }
  30.     mapping(uint => mapping(uint => mapping(uint => string))) public map;
  31.     function test() public
  32.     {
  33.         map[0][1][1] = "lalalalala";  //mapping数据类型还可以嵌套,相当于Python中的多维字典
  34.         //map[0]:mapping(uint => mapping(uint => string))
  35.         //map[0][1]:mapping(uint => string)
  36.         //map[0][1][1]:string
  37.     }
  38.    
  39. }

mapping(key => value) Mapping的相关语句:

(1)“mapping(type1 => type2) Mapping;”的作用是创建一个type1类型到type2类型的映射,映射组的名称为“Mapping”。

(2)“Mapping[key] = value;”的作用是:

①如果Mapping组中此前没有key这个键值,那么Mapping组中会添加key这个键值到value的映射。

②如果Mapping组中此前存在key这个键值,那么key键值的映射修改为value。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/595700
推荐阅读
相关标签
  

闽ICP备14008679号