第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > solidity数据类型(四)storage memory calldata modifier前置条件 继承 接口合

solidity数据类型(四)storage memory calldata modifier前置条件 继承 接口合

时间:2021-04-05 04:20:58

相关推荐

solidity数据类型(四)storage memory calldata modifier前置条件 继承 接口合

1 数据存储位置

数据测存储类型有storage 和 memory

函数的传入参数和返回参数 都是 memory类型(external函数的入参为calldata类型,只可读,不可重写)

函数局部变量、合约状态变量都是storage类型

memory总是会重新分配内存,不会释放内存,当有重名未使用的变量时,不会利用前者内存空间,而会重新分配新的空间

memory数据的位置标注可以修改,数据可读可修改

storage存储在EVM的storage区域,在交易执行之后,storage区域的数据会写回到合约账户的storage中

EVM的slot是32字节,因此在存储storage变量的时候,变量值小于32字节时会把多个变量打包存放在一个slot中。大于32字节的数据,slot中存放的是数据字节长度+长度值的字节数

多变量打包规则:

每一项都按低位对齐

基本数据类型选择合适的字节命名

struct和array会从一个新的slot开始存储,但是strut和array内部的数据还是按照上述打包规则打包存入slot

例如:uint128 a;uint256 b;uint128 c; 按照多量打包的规则应该写为:

uint128 a; uint128 c;uint256 b;

calldata的数据类型,标识的数据不能被修改也不能持久化

只能用于external函数的入参

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;contract CalldataContract {function calldataTest(uint8 [] array) external pure returns (uint8) {assert(array.length > 0 && array.length <= 10);uint8 sum = 0;// array[0] = 10; //external的入参数据类型为calldata 只读不可修改for(uint8 i=0;i<array.length;i++){sum += array[i];}return sum;}function memoryTest(uint8 [] array) public pure returns (uint8) {assert(array.length > 0 && array.length <= 10);uint8 sum = 0;array[0] = 10;//array数据类型为storage存储for(uint8 i=0;i<array.length;i++){sum += array[i];}return sum;}}

2 变量赋值

|数据类型|执行操作 |

|-----|–|

|1| 状态变量->状态变量 | 拷贝操作 |

|2| 状态变量->局部storage变量 | 指针(引用) |

|3| 状态变量->memory数据 | 拷贝操作 |

|4| 局部memory数据->状态变量 | 拷贝操作 |

|5| 局部memory数据->局部memory数据 | 指针拷贝(引用拷贝) |

|6| 局部memory数据->局部storage数据 | X不能进行转换 |

|7| 局部storage数据->状态变量 | 拷贝操作 |

|8| 局部storage数据->局部memory变量 | 拷贝操作 |

|9| 局部storage数据->局部storage变量 | 指针拷贝(引用拷贝) |

拷贝操作中 B数据的修改不会影响A

指针操作中 B数据的修改会影响A

//状态变量赋值给状态变量 执行拷贝操作contract StateToStateContract {uint8 [3] public arrayF = [1,2,3];uint8 [3] public arrayS;event LogUint8(uint8);function changeArray () public {uint8 i = 0;for(;i<3;i++){emit LogUint8(arrayF[i]);}arrayS = arrayF;arrayF[0] = 10;i=0;for(;i<3;i++){emit LogUint8(arrayS[i]);}} }

/*** 状态变量赋值给局部storage变量 执行引用传递指针操作**/contract StateToStateContract {uint8 [3] public arrayF = [1,2,3];event LogUint8(uint8);function changeArray () public {uint8 [3] storage arrayS;uint8 i = 0;for(;i<3;i++){emit LogUint8(arrayF[i]);}arrayS = arrayF;arrayF[0] = 10;i=0;for(;i<3;i++){emit LogUint8(arrayS[i]);}} }

/*** 状态变量赋值给局部memory变量 执行拷贝操作**/contract StateToStateContract {uint8 [3] public arrayF = [1,2,3];event LogUint8(uint8);function changeArray () public {uint8 [3] memory arrayS;uint8 i = 0;for(;i<3;i++){emit LogUint8(arrayF[i]);}arrayS = arrayF;arrayF[0] = 10;i=0;for(;i<3;i++){emit LogUint8(arrayS[i]);}} }

/*** 局部memory变量赋值给局部memory变量 执行引用传递指针操作**/contract StateToStateContract {event LogUint8(uint8);function changeArray () public {uint8 [3] memory arrayF = [1,2,3];uint8 [3] memory arrayS;uint8 i = 0;for(;i<3;i++){emit LogUint8(arrayF[i]);}arrayS = arrayF;arrayF[0] = 10;i=0;for(;i<3;i++){emit LogUint8(arrayS[i]);}} }

/**

局部memory变量赋值给状态变量 执行拷贝操作

**/

/**

局部storage变量赋值给状态变量 执行拷贝操作

**/

contract StateToStateContract {uint8 [3] public arrayF = [1,2,3];uint8 [3] public arrayS;event LogUint8(uint8);function changeArray () public {uint8 [3] storage array = arrayF;arrayS=array;uint8 i = 0;for(;i<3;i++){emit LogUint8(arrayF[i]);}array[0] = 10;i=0;for(;i<3;i++){emit LogUint8(arrayS[i]);}} }

/**

局部storage变量赋值给局部storage变量 执行指针引用操作

**/

/**

局部storage变量赋值给局部memory变量 执行拷贝操作

**/

3 函数修改器

modifier修饰符标识函数修改器 有函数名称 可以接受参数,方法内部的_;为修饰函数插入的地方

用来检查函数运行的前置条件和后置的清理工作

示例代码:

判断当前语句的执行地址需要是合约部署的账户地址

在切换账户后,再次执行应该报错

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;contract ModifierContract {uint public a = 0;address owner = msg.sender;event LogStringUint(string id,uint data);modifier modifierA(uint arga) { emit LogStringUint("modifierA before a=:",a);emit LogStringUint("modifierA before arga=:",arga);//identity msg require(owner==msg.sender,"not satisfify identity");_;emit LogStringUint("modifierA after a=:",a);emit LogStringUint("modifierA after arga=:",arga);}function modifierTest () public modifierA(a) returns(uint res) {emit LogStringUint("modifierTest1 a:",a);a = 5;emit LogStringUint("modifierTest2 a:",a);return a;}}

切换账户执行合约

不满足require判断,会报错

一个函数可以使用多个修改器验证前置条件,前置条件的验证顺序按照修改器顺序执行,后置条件的清理按照修改器逆向顺序执行 即前置和后置条件的执行顺序相反,先执行前置条件的最后执行后置条件

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;contract ModifierSummaryContract {uint public a = 0;event LogStringUint(string id,uint data);modifier modifierA(uint arga) { emit LogStringUint("modifierA before a=:",a);emit LogStringUint("modifierA before arga=:",arga);_;emit LogStringUint("modifierA after a=:",a);emit LogStringUint("modifierA after arga=:",arga);}modifier modifierB { emit LogStringUint("modifierB before a=:",a);// return;_;emit LogStringUint("modifierB after a=:",a);}function modifierTest () public modifierA(10) modifierB returns(uint res) {emit LogStringUint("modifierTest1 a:",a);a = 5;emit LogStringUint("modifierTest2 a:",a);return a;}}

执行的日志:

[

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA before a=:”,

“1”: “0”,

“id”: “modifierA before a=:”,

“data”: “0”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA before arga=:”,

“1”: “10”,

“id”: “modifierA before arga=:”,

“data”: “10”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierB before a=:”,

“1”: “0”,

“id”: “modifierB before a=:”,

“data”: “0”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierTest1 a:”,

“1”: “0”,

“id”: “modifierTest1 a:”,

“data”: “0”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierTest2 a:”,

“1”: “5”,

“id”: “modifierTest2 a:”,

“data”: “5”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierB after a=:”,

“1”: “5”,

“id”: “modifierB after a=:”,

“data”: “5”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA after a=:”,

“1”: “5”,

“id”: “modifierA after a=:”,

“data”: “5”

}

},

{

“from”: “0x417Bf7C9dc415FEEb693B6FE313d1186C692600F”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA after arga=:”,

“1”: “10”,

“id”: “modifierA after arga=:”,

“data”: “10”

}

}

]

修改器中可以包含return ,return语句之后的修改器不触发

再修改器函数return后,执行return之前的修改器的后置清理条件

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;contract ModifierSummaryContract {uint public a = 0;event LogStringUint(string id,uint data);modifier modifierA(uint arga) { emit LogStringUint("modifierA before a=:",a);emit LogStringUint("modifierA before arga=:",arga);_;emit LogStringUint("modifierA after a=:",a);emit LogStringUint("modifierA after arga=:",arga);}modifier modifierB { emit LogStringUint("modifierB before a=:",a);//return;_;emit LogStringUint("modifierB after a=:",a);}modifier modifierC { emit LogStringUint("modifierC before a=:",a);return; //return之后的语句不在执行,返回执行前面两个修饰器的后置条件_;emit LogStringUint("modifierC after a=:",a);}//C中有return 执行顺序 A前置 B前置 Creturn 之前的语句 B后置 A后置function modifierTest () public modifierA(10) modifierB modifierC returns(uint res) {emit LogStringUint("modifierTest1 a:",a);a = 5;emit LogStringUint("modifierTest2 a:",a);return a;}}

执行的日志:

[

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA before a=:”,

“1”: “0”,

“id”: “modifierA before a=:”,

“data”: “0”

}

},

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA before arga=:”,

“1”: “10”,

“id”: “modifierA before arga=:”,

“data”: “10”

}

},

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierB before a=:”,

“1”: “0”,

“id”: “modifierB before a=:”,

“data”: “0”

}

},

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierC before a=:”,

“1”: “0”,

“id”: “modifierC before a=:”,

“data”: “0”

}

},

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierB after a=:”,

“1”: “0”,

“id”: “modifierB after a=:”,

“data”: “0”

}

},

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA after a=:”,

“1”: “0”,

“id”: “modifierA after a=:”,

“data”: “0”

}

},

{

“from”: “0xDf9D0C45d97f134151a386E0AA23b09CA903c13f”,

“topic”: “0xfb812593d6d1d6fbf5e981f61205a76acc217dd9dcc7b95c4f58247fb09f2658”,

“event”: “LogStringUint”,

“args”: {

“0”: “modifierA after arga=:”,

“1”: “10”,

“id”: “modifierA after arga=:”,

“data”: “10”

}

}

]

4合约继承

solodity合约的继承是使用关键字is

当一个合约继承另一个合约时,只会部署一个合约,子合约会复制父合约的代码

构造函数的参数传递可以在继承时传递

在继承时传递或者通过构造器在构造函数时传递

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;contract LevelOne {uint8 num;constructor(uint8 numArg) public{num = numArg;}event LogUint8(string,uint8);function printNum() public {emit LogUint8("LevelOne",num);}}//继承时传递参数contract LevelTwoOne is LevelOne(2){//重写父合约的方法function printNum() public {emit LogUint8("LevelTwoOne",num);}}//构造函数中传递参数contract LevelTwoTwo is LevelOne{constructor() LevelOne(31) public{}//重写父合约的方法function printNum() public {emit LogUint8("LevelTwoTwo",num);}}//在构造函数中传递参数,调用父合约的PrintNum方法contract LevelTwoThree is LevelOne{constructor() LevelOne(31) public{}}

LevelTwoOne 部署日志:

[

{

“from”: “0xa42b1378D1A84b153eB3e3838aE62870A67a40EA”,

“topic”: “0xa9b4ee9b4192341ff2079d8152ddc2cdebd57d8a9df0609fa13cff40ef51d1f7”,

“event”: “LogUint8”,

“args”: {

“0”: “LevelTwoOne”,

“1”: 2

}

}

]

LevelTwoTwo 部署日志:

[

{

“from”: “0x3cA38E089Cd3BF3cF24Dabc40dF0c988075b2729”,

“topic”: “0xa9b4ee9b4192341ff2079d8152ddc2cdebd57d8a9df0609fa13cff40ef51d1f7”,

“event”: “LogUint8”,

“args”: {

“0”: “LevelTwoTwo”,

“1”: 31

}

}

]

LevelTwoThree 部署日志:

[

{

“from”: “0xa6165bbb69f7e8f3d960220B5F28e990ea5F630D”,

“topic”: “0xa9b4ee9b4192341ff2079d8152ddc2cdebd57d8a9df0609fa13cff40ef51d1f7”,

“event”: “LogUint8”,

“args”: {

“0”: “LevelOne”,

“1”: 31

}

}

]

函数继承多个函数时,后面的函数会重写前面的函数方法

super关键字,当使用super时,调用的是继承的该函数

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;contract LevelOneOne{event LogString(string);function printNum() public {emit LogString("LevelOneOne");}}contract LevelOneTwo{event LogString(string);function printNum() public {emit LogString("LevelOneTwo");}}//同时继承多个合约时,后面的合约会重写前面合约的同名方法contract LevelTwoOne is LevelOneOne,LevelOneTwo{function printNum() public {emit LogString("LevelTwoone");}//super关键字标识 方法为继承的方法//同时继承多个合约时,后面的合约会重写前面合约的同名方法function testSuper() public {super.printNum();}}contract LevelTwoTwo is LevelOneTwo,LevelOneOne{//override function function printNum() public {emit LogString("LevelTwoTwo");}//super- function is contract-inherited 's function function testSuper() public {super.printNum();}}

LevelTwoOne部署日志

printNum()日志:

[

{

“from”: “0xC1144C9dbf6F3489CE9C808a1Da653FB4465403d”,

“topic”: “0xa95e6e2a182411e7a6f9ed114a85c3761d87f9b8f453d842c71235aa64fff99f”,

“event”: “LogString”,

“args”: {

“0”: “LevelTwoone”

}

}

]

testSuper()日志:

[

{

“from”: “0xC1144C9dbf6F3489CE9C808a1Da653FB4465403d”,

“topic”: “0xa95e6e2a182411e7a6f9ed114a85c3761d87f9b8f453d842c71235aa64fff99f”,

“event”: “LogString”,

“args”: {

“0”: “LevelOneTwo”

}

}

]

LevelTwoTwo部署日志

printNum()日志:

[

{

“from”: “0xC8CF29d9D1595a3588AD36E6349A0E9a5b632720”,

“topic”: “0xa95e6e2a182411e7a6f9ed114a85c3761d87f9b8f453d842c71235aa64fff99f”,

“event”: “LogString”,

“args”: {

“0”: “LevelTwoTwo”

}

}

]

testSuper()日志:

[

{

“from”: “0xC8CF29d9D1595a3588AD36E6349A0E9a5b632720”,

“topic”: “0xa95e6e2a182411e7a6f9ed114a85c3761d87f9b8f453d842c71235aa64fff99f”,

“event”: “LogString”,

“args”: {

“0”: “LevelOneOne”

}

}

]

抽象合约

如果一个合约中至少有一个方法没有被实现,那么这个合约就是抽象合约

抽象合约无法被编译部署

一个合约继承了抽象合约但是没有实现抽象合约内方法的话,也会被定义为抽象合约

抽象合约中有几个为实现的方法,继承的子合约中就需要实现几个方法

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;/*** 抽象合约 */contract CalcContract{constructor()public{}//定义抽象方法function calc(uint8 a,uint8 b) public view returns(uint8);// function minus(uint8 a,uint8 b) public returns(uint8);function mul(uint a,uint b)public pure returns(uint){return a*b;}}// /**// * 继承抽象合约// */contract Add is CalcContract{//实现抽象方法function calc(uint8 a,uint8 b) public view returns(uint8){return a + b;}function getBalance()public view returns(address addr,uint256 num){//return(msg.sender,msg.sender.balance);return(address(this),address(this).balance); }}

接口合约

接口合约和抽象合约类似 定义合约方法 用于子合约继承实现

接口合约比较严格

不能继承其它合约和接口

不能定义构造函数

不能定义结构体

不能定义变量

不能定义枚举

可以定义事件,通过emit抛出

5 solidity库

通过library 关键字标识solidity库

库的调用方式是delegatecall方式

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;library TestLibrary{struct Student{uint32 id;string name;}function add(uint8 a,uint8 b) public pure returns(uint8) {return a + b;}}contract RefLibrary{TestLibrary.Student tim = TestLibrary.Student(1,"tim");function getTim() public view returns(uint32,string){return(tim.id,tim.name);}function callAdd(uint8 a,uint8 b) public pure returns(uint8){return TestLibrary.add(a,b);}}

引入solidity库

通过import引入目录下的sol合约

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;import "./Calc.sol";import "./AddLib.sol";contract AddCalc is Calc{function calc (uint a,uint b)public pure returns(uint){return AddLib.add(a,b);}}

using…for

让库函数attach到指定的类型上,指定的类型具备库函数的方法

// SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;library CalcLib {function add(uint8 a, uint8 b) public pure returns(uint8){return a + b;}function sub(uint8 a, uint8 b) public pure returns(uint8){return a - b;}}contract UsingForContract {using CalcLib for uint8;function add(uint8 a,uint8 b) public pure returns(uint8) {return a.add(b);} function sub(uint8 a,uint8 b) public pure returns(uint8) {return a.sub(b);} }

// // SPDX-License-Identifier: GPL-3.0pragma solidity ^0.4.0;library CalcLib{function sum(uint8[] storage arrs)public view returns(uint8){uint8 totls=0;for(uint8 i=0;i<arrs.length;i++){totls+=arrs[i];}return totls;}}contract usingForContract{using CalcLib for uint8[];uint8[] array=[2,3,4,5];function sum()public view returns(uint8){return array.sum();}}

6 solc编译合约

solc -o build --combined-json abi,bin getNum.sol

-o参数表示输出目录的名称 --combined-json以json的形式组合输出后面的问价 abi接口 bin十六进制输出合约的字节码

solc -o build --abi --bin getNum.sol

合约中有导入库的情况时:

在编译合约时需要设置导入合约的文件前缀

solc /=/ Hello.sol

举例 import “/lib/sub/Sub.sol”

solc /lib/sub=/lib/sub Hello.sol

solidity数据类型(四)storage memory calldata modifier前置条件 继承 接口合约 导入库 using...for solc编译

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。