赞
踩
S1:下载安装Geth、Mist客户端
S2:初始化创世纪节点
定义一个配置文件genesis.json
- {
- "config": {
- "chainId": 666,
- "homesteadBlock": 0,
- "eip150Block": 0,
- "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "eip155Block": 0,
- "eip158Block": 0,
- "byzantiumBlock": 0,
- "constantinopleBlock": 0,
- "petersburgBlock": 0,
- "istanbulBlock": 0,
- "ethash": {}
- },
- "nonce": "0x0",
- "timestamp": "0x5ddf8f3e",
- "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "gasLimit": "0x47b760",
- "difficulty": "0x00002",
- "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "coinbase": "0x0000000000000000000000000000000000000000",
- "alloc": { },
- "number": "0x0",
- "gasUsed": "0x0",
- "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
- }
通过如下指令,利用配置文件初始化创世块:
geth -datadir data0 init genesis.json
上面的命令,会读取genesis.json文件,根据其中的内容,将创世区块写入到区块链中。如果看到log信息中含有Successfully wrote genesis state字样,说明初始化成功。
在系统文件夹中生成data0,geth?keystore?
S3:启动私有链节点
通过如下指令,即可启动:
geth -datadir data0 console
成功出现如下提示:
注:这里后面INFO输出Looking for peers,不影响操作!
S4:体验挖矿
启动挖矿指令:
miner.start()
可以看到DAG percentage逐渐增大
之后不想挖矿后,停止挖矿指令:
miner.stop()
挖矿收入检查:
eth.getBalance(eth.accounts[0])
智能合约概述 — Solidity develop 文档 (solidity-cn.readthedocs.io)
基于以太坊的智能合约开发教程【Solidity】_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
Remix - Solidity IDE - 中文版 (hubwiz.com)
- pragma solidity ^0.4.0;
- //^0.4.0代表向上版本兼容,编译器版本最高到0.5.0但不包括0.5.0
- contract Helloworld{
- string Myname="tyl";
- //view 修饰函数只能读取状态变量,不消耗gas
- function getName() public view returns(string){
- return Myname;
- }
- function changeName(string _newName) public{
- Myname=_newName;
- }
- //pure 修饰函数不能改也不能读状态变量,不消耗gas
- function pureTest(string _newName) public pure returns(string){
- return _newName;
- }
- }
1、Solidity 旧版本只有constant,新版本将constant拆成了view和pure。view的作用和constant一模一样,可以读取状态变量但是不能改;pure则更为严格,pure修饰的函数不能改也不能读状态变量,否则编译通不过。
2、pragma solidity ^0.4.0; //^0.4.0代表向上版本兼容,编译器版本最高到0.5.0但不包括0.5.0
- pragma solidity ^0.4.0;
- contract dataClass{
- //布尔类型 bool 数据操作:逻辑与、逻辑或、逻辑非 ||、 && 、!
- int num1=100;
- int num2=200;
- function boolcheck() public view returns(bool){
- return num1==num2;
- }//返回false
- function boolcheck1() public view returns(bool){
- return num1!=num2;
- } //返回true
-
-
- //整型 int=int256 uint=uint256 数据操作:加减乘除求余、求平方 +-*/%、**
- function intcheck(uint a,uint b) public pure returns(uint){
- return a**b;
- } //计算a的b次方
-
- //位运算:按位与、按位或、按位取反、按位异或、左移、右移 &、|、~、^、<<、>>
- uint8 a=3; uint8 b=4;
- function weicheck() public view returns(uint8){
- return a|b;
- }//按位或,结果为7
-
- //整型字面量:在solidity里面运算是计算出结果再赋值
- function IntergerTest() public pure returns(uint){
- uint num=1/2*1000;
- return num;
- }//返回500
-
- //字节(数组)类型:bytes1(byte)、bytes2...bytes32,长度固定且内部数据不可修改
- //属性:length 可以进行比较,位运算
- bytes9 name=0xe69d8ee79fa5e681a9;
- function byteTest() spublic pure returns(uint){
- byte num=0x7a;
- return num.length;
- }//返回1
-
- function getIndex(uint index) public view returns(byte){
- return name[index];
- }//按照index获得字节数组的值
-
- }
动态字节数组:bytes num=new bytes();长度、内部数据均可修改,push方法和修改长度,均是在数组末尾变化
- pragma solidity ^0.4.0;
- contract DynamicByte{
- bytes public num=new bytes(2);//创建动态字节数组
-
- function InitNum() public{
- num[0]=0x12;
- num[1]=0x34;
- }//初始化数组
-
- function getlength() public view returns(uint){
- return num.length;
- }//获取数组长度
-
- function setlength() public{
- num.length=5;
- }//修改数组长度
-
- function pushTest() public{
- num.push(0x56);
- }//push方法在数组末尾追加数据
-
- }
- pragma solidity ^0.4.0;
- contract StringTest{
- string name='tyl';//0x74796c
- string name1="李知恩";//0xe69d8ee79fa5e681a9
-
- function getlength() view returns(uint){
- return bytes(name).length;
- }//获得字符串的字节长度
-
- function getstrValue() view returns(string){
- return name;
- }//获得字符串的str值
-
- function getValue() view returns(bytes){
- return bytes(name);
- }//获得字符串的bytes值
-
- function getValue1() view returns(bytes){
- return bytes(name1);
- }//获得字符串的bytes值
-
-
- function getfirst() view returns(byte){
- return bytes(name)[0];
- }//获得字符串首个字节存储的值
-
- function setstrValue(){
- bytes(name)[0]='T';
- bytes(name)[1]='Y';
- bytes(name)[2]='L';
- }//按字节修改字符串的值
- }
字符串变量无法直接获得长度和修改字符串的值,需要进行bytes(字符串)强制转换后才能操作前面的操作。
- pragma solidity ^0.4.0;
- contract StrTest{
- bytes9 name= 0xe69d8ee79fa5e681a9;
-
- function change1() public view returns(bytes1){
- return bytes1(name);
- }//0xe6
-
- function change2() public view returns(bytes10){
- return bytes10(name);
- }//0xe69d8ee79fa5e681a900
- }
固定长度字符节数组长的变短,截取前面部分;短的变长的,在后面添0。
- pragma solidity ^0.4.0;
- contract StrTest1{
- bytes9 name=0xe69d8ee79fa5e681a9;
-
- function fixByte2dynamicByte() public view returns(bytes){
- bytes memory newByte=new bytes(name.length);
- for(uint i=0;i<name.length;i++){//细节问题:for循环里要求是uint变量
- newByte[i]=name[i];
- }
- return newByte;
- }
- }
- pragma solidity ^0.4.0;
- contract StrTest1{
- bytes9 name=0xe69d8ee79fa5e681a9;
- function fixByte2dynamicByte() public view returns(bytes){
- bytes memory newByte=new bytes(name.length);
- for(uint i=0;i<name.length;i++){
- newByte[i]=name[i];
- }
- return newByte;
- }
- function bytes2string() public view returns(string){
- bytes memory IU=fixByte2dynamicByte();
- return string(IU);
- }//返回"李知恩"
- }
小结:bytes与string可互相转换。string(字节数组)、bytes(字符串)
- pragma solidity ^0.4.0;
- contract StrTest2{
- function bytes32Tostring(bytes32 _newname) public pure returns(string){
- uint count=0;
-
- for(uint i=0;i<_newname.length;i++){
- bytes1 char=_newname[i];
- if(char!=0){
- count++;
- }
- }//找到字节数组中有用数据个数
-
- bytes memory newname=new bytes(count);
-
- for(uint j=0;j<count;j++){
- newname[j]=_newname[j];
- }//固定字节数组转换为动态字节数组
-
- return string(newname);//最终实现固定字节数组转换为string
- }
- }
- pragma solidity ^0.4.0;
- contract ArrayTest{
- //固定数组初始化
- uint[5] arr=[1,2,3,4,5];
- //获取数组元素并修改
- function Init() public{
- arr[0]=100;
- arr[1]=200;
- }
- //获取数组元素内容
- function getArrayContent() public view returns(uint[5]){
- return arr;
- }
- //对数组元素求和
- function getGrade() public view returns(uint){
- uint grade=0;
- for(uint i=0;i<arr.length;i++){
- grade+=arr[i];
- }
-
- return grade;
- }
-
- }
固定数组没有push方法,也无法修改数组的length
- pragma solidity ^0.4.0;
- contract ArrayTest1{
- // 可变数组初始化
- uint[] grade=[1,2,3,4,5];
- //获取数组元素内容
- function getContent() public view returns(uint[]) {
- return grade;
- }
- //获取可变数据长度
- function getLength() public view returns(uint){
- return grade.length;
- }
- //获取可变数组元素并修改
- function changeContent() public{
- grade[0]=100;
- grade[1]=200;
- }
- //对数组元素求和
- function add() public view returns(uint){
- uint sum=0;
- for(uint i=0;i<grade.length;i++){
- sum+=grade[i];
- }
- return sum;
- }
- //改变可变数组长度(缩短,只保留前面的数组元素)
- function changLength() public{
- grade.length=2;
- }
- //改变可变数组长度(增长,在数组后面添0)
- function changLength1() public{
- grade.length=10;
- }
- //push方法在数组后面追加
- function pushContent() public{
- grade.push(6);
- }
-
- }
定义静态二维数组时,行数和列数和其他语言不同,与其他语言刚好相反:数据类型[列数][行数]=[…….]。但在数组操作时,依旧是一样。静态二维数组同样不能改变数组长度
- pragma solidity ^0.4.0;
- contract ArrayTest2{
- //静态数组定义行数和列数刚好相反!!!
- uint[2][3] grade=[[1,2],[3,4],[5,6]];
- //获取数组内容
- function getContent() public view returns(uint[2][3]){
- return grade;
- }
-
- function getRowLength() public view returns(uint){
- return grade.length;
- }//3行
-
- function getColumnsLength() public view returns(uint){
- return grade[0].length;
- }//2列
-
- function add() public view returns(uint){
- uint sum=0;
- for(uint i=0;i<grade.length;i++){//行
- for(uint j=0;j<grade[0].length;j++){//列
- sum+=grade[i][j];//取数组元素依旧和之前的语言一样
- }
- }
- return sum;
- }
- }
动态二维数组,可修改数组长度,暂时还无法支持动态二维数组作为返回值,获得数组内容
- pragma solidity ^0.4.0;
- contract ArrayTest3{
- //定义动态二维数组
- uint[][] grade=[[1,2],[3,4],[5,6]];
-
-
- function getRowLength() public view returns(uint){
- return grade.length;
- }//3
-
- function getColumnsLength() public view returns(uint){
- return grade[0].length;
- }//2
-
- //改变行数
- function setRowLength() public{
- grade.length=4;
- }
- //改变列数,可针对任一行修改列数。
- function setColumnsLength() public {
- grade[0].length=4;
- }
-
- function add() public view returns(uint){
- uint sum=0;
- for(uint i=0;i<grade.length;i++){
- for(uint j=0;j<grade[i].length;j++){//注意和静态数组差别,每行的列数不一定相同
- sum+=grade[i][j];
- }
- }
- return sum;
- }
-
- }
一般用于输入需求,返回数组字面量时,返回参数列表以数组字面量最小类型为准。
- pragma solidity ^0.4.0;
- contract ArrayTest3{
-
- function getArray1() public pure returns(uint8[4]){
- return [1,2,3,4];
- }//最小类型为uint8
-
- function getArray2() public pure returns(uint16[4]){
- return [256,2,3,4];
- }//最小类型为uint16
-
- function getArray3() public pure returns(uint[4]){
- return [uint(1),2,3,4];
- }//可以强制将字面量转换为来适应返回参数列表类型
-
- function add(uint[4] grade) public pure returns(uint){
- uint sum=0;
- for(uint i=0;i<grade.length;i++){
- sum+=grade[i];
- }
- return sum;
- } //数组字面量用于输入
-
- }
address 在存储上和uint160一样,且二者可以互相转换,地址之间也可以进行比较大小
- pragma solidity ^0.4.0;
- contract arrayTest{
-
- address public account=0xca35b7d915458ef540ade6068dfe2f44e8fa733c;
-
- function changeIt() public view returns(uint160){
- return uint160(account);
- }//地址转换为uint160:1154414090619811796818182302139415280051214250812
-
- function Itchange() public view returns(address){
- return address(changeIt());
- }//uint160转换为地址:0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c
-
- }
地址分为外部账户地址和合约账户地址,合约是由外部账户发布的合约,每个合约都有自己的地址。和外部账户一样,合约账户也可以有钱(以太币)
- pragma solidity ^0.4.0;
- contract arrayTest1{
- //payable关键字,允许转账操作(这里是外部账户转账给合约账户)
- function pay() public payable{
-
- }
- //返回合约账户地址
- function getAddress() public view returns(address){
- return this;
- }//0x038f160ad632409bfb18582241d9fd88c1a072ba
-
- //this关键字代表合约账户,账户都有balance(钱),这里“钱”单位默认是wei,返回合约账户的钱
- function getBalance() public view returns(uint){
- return address(this).balance;
- }
-
- //可以获得任意账户的钱
- function getBalance_by_addr(address account) public view returns(uint){
- return account.balance;
- }
-
-
- }
外部账户之间进行转账: account.transfer(msg.value);
外部账户向合约账户转账:address(this).transfer(msg.value);+回滚函数
其中msg.value是全局变量,代表转账的数量
- pragma solidity ^0.4.0;
- contract arrayTest2{
- //运行该合约的账户向外部account账户进行转账
- function transfer() public payable{
- address account=0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
- account.transfer(msg.value);
- }
- //按照地址获得账户余额
- function getBlance_by_addr(address account) public view returns(uint){
- return account.balance;
- }
- //外部账户向改合约账户进行转账,必须要有回滚函数
- function transfer1() public payable{
- address(this).transfer(msg.value);
- }
- //必须要有的回滚函数!!!
- function() public payable{
-
- }
-
- }
account.transfer(msg.value)中msg.value可以直接用相应的值替换,e.g. account.transfer(10 ether);
- function sendMoney() public payable returns(bool){
- address account=0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
- return account.send(10 ether);
- }//send方法比较底层,如果不传入相应的转账金额,不会报错,只会返回false
-
- function transfer() public payable{
- address account=0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
- account.transfer(msg.value);
- }//transfer方法,如果不传入相应的转账金额,会进行报错提示
- pragma solidity ^0.4.0;
- contract mappingTest{
- //定义两个mapping类型的变量
- mapping(address=>uint) public idmapping;
- mapping(uint=>string) public namemapping;
- //用于代表注册的人数
- uint sum=0;
- //注册,主要是合约调用者的地址=>id;id=>姓名两组映射关系
- function register(string name) public{
- address account=msg.sender;
- sum++;
- idmapping[account]=sum;
- namemapping[sum]=name;
- }
- //根据地址来获得id
- function getIdbyAddr(address account) public view returns(uint){
- return idmapping[account];
- }
- //根据id来获得姓名
- function getNamebyId(uint id) public view returns(string){
- return namemapping[id];
- }
- }
函数一般类型:
function 函数名(参数列表){private|internal|external|public}[pure|constant|view|payable][returns(返回值类型)]
函数重载会遇到一个函数匹配的问题,例如add(1)与函数add(uint8)和add(uint)两个都匹配,发生冲突故报错!
其次参数列表类型是uint160和address时,无论输入的参数是什么类型,都会发生冲突,因为这两个本身机器是无法区分的。
- pragma solidity ^0.4.0;
- contract Test{
-
- string public name;
- uint public id;
- function set(string _name,uint _id) public{
- name=_name;
- id=_id;
- }
-
- function test1() public{
- set("李知恩",123);
- }
- //通过这种给参数直接赋值的方式可以不考虑函数列表的先后顺序
- function test2() public{
- set({_name:"李知恩",_id:123});
- }
-
- }
- pragma solidity ^0.4.0;
- contract Test{
- //函数返回值可以有名称
- function test1() public pure returns(uint mul){
- return 123;
- }
- //函数返回值可以不用return返回,直接给返回值赋值
- function test2() public pure returns(uint mul){
- mul=123;
- }
- //函数返回值最终以return为主
- function test3() public pure returns(uint mul){
- mul=123;
- uint a=100;
- return a;
- }
- //函数可有多个返回值
- function test4() public pure returns(uint a, uint b){
- return(10,20);
- }
-
- }
全局变量名称在局部变量里可以出现重名的,此时修改局部变量不会影响全局变量。同时在函数里面,也不能出现重复定义的变量!
- pragma solidity ^0.4.0;
- contract test{
- //全局变量
- uint public a=100;
-
- function test0() public view returns(uint){
- return a;
- }//返回100
-
- function test1() public pure returns(uint){
- uint a=200;
- return a;
- }//重新定义局部变量a,返回200,但全局变量a依旧是100
-
- function test2(uint a) public pure returns(uint){
- // uint a=300;无法重复定义a,在参数列表内出现了重复
- a=300;
- return a;
- }//返回300
- }
- pragma solidity ^0.4.0;
- //public修饰符,可以在合约内部,继承合约内部,外部调用
- contract father{
- //public修饰函数
- function dahan() public pure returns(string){
- return "dahan";
- }
- //合约内部调用
- function publictest() public pure returns(string){
- return dahan();
- }
-
- }
- contract son is father{
- //public修饰 继承合约可继承还可直接调用
- function test() public pure returns(string){
- return dahan();
- }
-
- }
- //=========================================================
-
- //private修饰符,函数只能被本合约内部调用
- contract father1{
- function dahan() private pure returns(string){
- return "dahan";
- }
- //合约内部调用
- function privatetest() public pure returns(string){
- return dahan();
- }
- }
- contract son1 is father1{
- //private修饰符,函数不能被继承合约继承和调用
- /* function test() public pure returns(string){
- return dahan();
- }*/
-
- }
- //==========================================================
-
- //internal修饰符,函数只能被合约内部调用和继承合约内部调用
- contract father2{
- function dahan() internal pure returns(string){
- return "dahan";
- }
- //合约内部调用
- function internaltest() public pure returns(string){
- return dahan();
- }
- }
- contract son2 is father2{
- //继承合约内部调用
- function test() public pure returns(string){
- return dahan();
- }
-
- }
- //==========================================================
-
- //external修饰符,只能在外部调用,或者在合约内部和继承合约内部间接调用(实际也是外部调用)
- contract father3{
- function dahan() external pure returns(string){
- return "dahan";
- }
- //无法直接在合约内部调用
- /* function externaltest() public pure returns(string){
- return dahan();
- }*/
-
- //间接调用
- function externaltest() public view returns(string){
- return this.dahan();
- }
- }
- contract son3 is father3{
- //无法直接在继承合约内部调用
- /* function test() public pure returns(string){
- return dahan();
- }*/
-
- //间接调用
- function test() public view returns(string){
- return this.dahan();
- }
-
- }
- //通过另外不相关的合约,new一个合约对象,也可以间接调用
- contract externaltest{
- father3 f=new father3();
- function test() public view returns(string){
- return f.dahan();
- }
- }
变量赋值给变量,是值传递的方式;形参传入的是副本拷贝,修改它的值不会影响原来的变量。
- pragma solidity ^0.4.0;
- contract test{
-
- uint public a=100;
- uint public b=a;//变量赋值给变量,值传递
-
- function changeIt() public returns(uint){
- b=200;
- return b;//修改b不会影响原来的变量a
- }
-
- function changeIt1(uint m) public pure returns(uint){
- m++;
- return m;
- }
-
- function changeIt1test() public view{
- changeIt1(a);//形参传入的是变量的副本拷贝,不会影响原来的变量。
- }
- }
作用与view差不多,只能读取变量,没法修改变量,目前支持int、uint、string、bytes1-32
- pragma solidity ^0.4.0;
- contract constantTest{
- // 测试可以支持的数据类型
- uint constant num=100;
- uint public num1=100;
- int constant num2=100;
- string constant num3="100";
- bytes1 constant num4=0x11;
- bytes constant public num5=new bytes(2);//编译没有报错,但无法修改,只能是0x0000;
-
- //constan全局变量无法修改,编译报错!
- /* function changeIt() public{
- num=0;
- }*/
-
-
- function change() public pure returns(string){
- num5[0]=0x12;
- num5[1]=0x12;
- return string(num5);
- }//并没有修改成功!
-
- function changeIt() public constant returns(uint){
- num1=200;
- return num1;
- }//返回200,但是全局变量num1依旧是100
- }
新版本用 constructor(…) {…}作为构造函数
- pragma solidity ^0.4.0;
- contract Test{
- uint public a;
- function Test() public{
- a=100;
- }
-
- }
-
- contract Test1{
- uint public b;
- function Test1(uint _b) public{
- b=_b;
- }
- }
-
- contract Test2{
- address public owner;
- constructor() public{
- owner=msg.sender;
- }
- }
函数修饰符函数modifier 函数名(参数列表){…}
- pragma solidity ^0.4.0;
- contract modifierTest{
-
- address public owner;
- uint public num=0;
-
- constructor() public{
- owner=msg.sender;
- }
-
- modifier Onlyowner() {
- require(msg.sender==owner);
- _;
- }//定义的函数修饰符函数,_;在满足require的条件时,会被替换成num=100;否则函数回滚,不会执行num=100;
-
- function change() Onlyowner public{
- num=100;
- }//用Onlyowner修饰
-
- }
modifier修饰函数作用举例1
- contract mappingTest{
- //定义两个mapping类型的变量
- mapping(address=>uint) public idmapping;
- mapping(uint=>string) public namemapping;
- //用于代表注册的人数
- uint sum=0;
-
- modifier control(){
- require(idmapping[msg.sender]==0);
- _;
- }//通过这个修饰,可以确保每个账户只能注册一次!
- //注册,主要是合约调用者的地址=>id;id=>姓名两组映射关系
- function register(string name) control public{
- address account=msg.sender;
- sum++;
- idmapping[account]=sum;
- namemapping[sum]=name;
- }
- //根据地址来获得id
- function getIdbyAddr(address account) public view returns(uint){
- return idmapping[account];
- }
- //根据id来获得姓名
- function getNamebyId(uint id) public view returns(string){
- return namemapping[id];
- }
- }
modifier修饰函数作用举例2
- contract modifierTest2{
-
- uint public level=9;
-
- string public name="李知恩";
-
- uint public age=20;
- //modifier可以有参数列表
- modifier controlLevel(uint _level){
- require(level>_level);
- _;
- }
- //不同level才能有不同的权限!
- function changename() controlLevel(10) public{
- name="IU";
- }
-
- function changeage() controlLevel(5) public{
- age=18;
- }
-
- }
一个函数可以被多个modifier函数修饰符修饰,且执行顺序非常关键。(实际上就是按照修饰符顺序,依次执行,遇到_;会将后面的modifier函数,直接嵌入替换即可!)
- contract modifierTest3{
-
- uint public a;
- modifier mod1 {
- a=1;
- _;
- a=2;
- }
- modifier mod2{
- a=3;
- _;
- a=4;
- }
- //执行顺序:a=1,a=3,a=100,a=4,a=2
- function change() mod1 mod2 public{
- a=100;
- }//最终a=2
-
- //执行顺序:a=3,a=1,a=100,a=2,a=4
- function change1() mod2 mod1 public{
- a=100;
- }//最终a=4
-
- }
一、合约支持连续继承:儿子继承父亲,父亲继承祖父
- contract father is grandfater{...}
- contract son is father{...}
1、修饰变量的修饰符在继承中作用:默认、public、internal 可以被继承,private不能被继承,且修饰变量没有external
2、修饰函数的修饰符在继承中的作用:public internal、external可以被继承,private不能被继承
二、合约支持多重继承:儿子继承父亲和母亲
- contract son is mom,father{
- /*1、继承的属性如果mon和father里面都有,那么按照继承的顺序(这里是mom,father),选择最后一个继承者(这里是father)覆盖掉其他的合约属性*/
-
- //2、自身的属性如果和is后面的父辈合约重复了,那么自身属性会覆盖掉其他合约属性
-
- //3、继承时发生的函数重载以自身为准,父辈合约之间发生函数冲突,也是和属性一样,按继承顺序的最后一个继承者为准
-
- }
selfdestruct(合约发布者的地址)
- pragma solidity ^0.4.0;
- contract selfdestructTest{
-
- uint public money;
- address owner;
- constructor() public{
- owner=msg.sender;
- }
-
- function increase() public returns(uint){
- money++;
- return money;
- }
-
- //销毁合约
- function kill() public{
- if(msg.sender==owner){
- selfdestruct(owner);
- }
- }
- }
1、private 不能被继承,不能在外部被调用,可以在内部被调用
2、internal可以在内部被调用,不能在外部被调用,可以被继承
3、external 不能在内部被调用,只能够在外部调用,可以被继承,如果强行执行,通过”地址.“
4、public权限最大,可以在外部和内部调用,可以被继承
5、pure不会读取全局变量,更不会修改全局变量,一个固定的输入就会有一个固定的输出
6、constant在函数中,和view相同,在全局变量中,只用于bytes1-32,uint,int,string代表数据不能被修改
7、view只读取全局变量的值,不修改它,不消耗gas
8、payable转账的时候必须要加的关键字
9、命名参数{形参1名字:值1,形参2名字:值2}
10、函数可以有多个返回值
public 修饰变量时,会默认生成一个getter方法
- pragma solidity ^0.4.0;
- contract getter{
- uint public num=100;
- //相当于生成了下面注释的getter方法,external属性的
- /* function num() external view returns(uint){
- return num;
- }*/
-
- function getnum() public view returns(uint){
- return this.num();
- }
-
- mapping(uint=>string) public map;
-
- constructor() public{
- map[0]="李知恩";
- map[1]="IU";
- mapx[0][1][2]="IU";
- }
- //mapping类型比较特殊,生成的getter方法带有输入参数
- /* function map(uint key) external view returns(string){
- return map[key];
- }*/
-
- function getmap(uint key) public view returns(string){
- return this.map(key);
- }
- //复杂一点的mapping原理也是如上面所述的原理,这里带三个输入参数
- mapping(uint=>mapping(uint=>mapping(uint=>string))) public mapx;
-
- }
状态变量总是存储在存储区storage中。
- pragma solidity ^0.5.0;
-
- contract DataLocation {
-
- // storage
- uint stateVariable;
- uint[] stateArray;
- }
此外,不能显式地标记状态变量的位置。
- pragma solidity ^0.5.0;
-
- contract DataLocation {
-
- uint storage stateVariable; // 错误
- uint[] memory stateArray; // 错误
- }
函数参数包括返回参数都存储在内存memory中。
- pragma solidity ^0.5.0;
-
- contract DataLocation {
-
- // storage
- uint stateVariable;
- uint[] stateArray;
-
- function calculate(uint num1, uint num2) public pure returns (uint result) {
- return num1 + num2
- }
- }
此处,函数参数 uint num1
与 uint num2
,返回值 uint result
都存储在内存中。
值类型的局部变量存储在内存中。但是,对于引用类型,需要显式地指定数据位置。
- pragma solidity ^0.5.0;
-
- contract Locations {
-
- /* 此处都是状态变量 */
-
- // 存储在storage中
- bool flag;
- uint number;
- address account;
-
- function doSomething() public {
-
- /* 此处都是局部变量 */
-
- // 值类型
- // 所以它们被存储在内存中
- bool flag2;
- uint number2;
- address account2;
-
- // 引用类型,需要显示指定数据位置,此处指定为内存
- uint[] memory localArray;
- }
- }
不能显式覆盖具有值类型的局部变量。
- function doSomething() public {
-
- /* 此处都是局部变量 */
-
- // 值类型
- bool memory flag2; // 错误
- uint Storage number2; // 错误
- address account2;
-
- }
外部函数的参数(不包括返回参数)存储在Calldata中。
举例说明
- pragma solidity ^0.4.0;
- contract memoryTest{
- //状态变量,默认是storage,且不能显示说明!
- uint[] public arrx;
- /* uint[] memory public arrx;
- uint[] storage public arrx;*/
-
- function test(uint[] array) public returns(uint){
- //array存储在memory内,将值传递给存储在storage内的arrx
- arrx=array;
- //这里arrx由于是数组,属于引用变量,因此存储都在storage里的Z和arrx等同,且数组在storage内可以修改长度
- uint[] storage Z=arrx;
-
- Z[0]=10;
-
- Z.length=10;
- //由于Y是存储在memory的,它和arrx除了赋值的关系外,并没有等价的关系,且不能修改长度,Y修改对arrx不影响
- uint[] memory Y=arrx;
- //Y.length=20;
- Y[1]=20;
- }
-
- function test2() public view returns(uint[]){
- return arrx;
- }//返回整个数组内容
-
- function test3() public view returns(uint){
- return arrx.length;
- }//返回数组长度
- }
Solidity中,变量类型有以下几大类:
地址类型表示以太坊地址,长度为20字节。地址可以使用.balance
方法获得余额,也可以使用.transfer
方法将余额转到另一个地址。
- address x = 0x212;
- address myAddress = this;
-
- if (x.balance < 10 && myAddress.balance >= 10)
- x.transfer(10);
Solidity中,有一些数据类型由值类型组合而成,相比于简单的值类型,这些类型通常通过名称引用,被称为引用类型。
引用类型包括:
- pragma solidity ^0.4.0;
- contract structTest{
- //结构体的定义
- struct student{
- uint grade;
- string name;
- }
- //结构体的定义
- struct student1{
- uint grade;
- string name;
- // student1 stu;结构体内部不能包含自己本身,但是可以是动态长度的数组,也可以是映射
- student1[] stu;
- mapping(uint=>student1) hahah;
- }
-
-
- //结构体的初始化
- function init() public pure returns(uint,string){
- /*struct在函数体内默认是storage,而具体画的结构体student(100, "IU");则存储在memory中,因此需要显示定义结构体指针s在memory*/
- student memory s=student(100, "IU");
- return(s.grade,s.name);
- }
- //初始化的第二种方式
- function init2() public pure returns(uint,string){
- student memory s =student({grade: 100, name: "IU1"});
- return(s.grade,s.name);
- }
-
- }
初始化结构体时不能初始化mapping,且操作结构体内的mapping需要storage类型
- pragma solidity ^0.4.0;
- contract structTest{
- //结构体的定义
- struct student{
- uint grade;
- string name;
- mapping(uint=>string) map;
- }
- student IU;//1、默认是storage类型,只有storage类型才能操作结构体内的mapping
-
- //结构体的初始化
- function init() public returns(uint,string,string){
- //结构体初始化不需要初始化mapping
- student memory s=student(100, "IU");
- //2、memory对象不能操作结构体内的mapping
- //s.map[0]="李知恩";编译出错
- //3、通过将memory对象s赋值给storage对象,才能操作结构体内的mapping
- IU=s;
- IU.map[0]="李知恩";
- return(s.grade,s.name,IU.map[0]);
- // return(IU.grade,IU.name,IU.map[0]);返回值一样
- }
- }
前提:1、函数必须是internal 2、不能直接将形参赋值给storage指针
- pragma solidity ^0.4.0;
- contract structTest{
-
- //结构体的定义
- struct student{
- uint grade;
- string name;
-
- }
- /*1、必须是internal修饰 2、结构体变量stu是storage指针,不能和memory指针直接赋值(这就好像两个指向不同区域的指针是没法赋值一样的意思)*/
- function test1(student memory s) internal{
- student stu=s;
- }//编译不通过
- //默认就是memory,编译不通过
- /* function test1(student s)internal{
- student stu=s;
- }*/
- //编译通过了
- /* function test1(student storage s)internal{
- student stu=s;
- }*/
-
- }
情况1:storage转storage
- pragma solidity ^0.4.0;
- contract structTest{
- //结构体的定义
- struct student{
- uint grade;
- string name;
- }
- //stu是状态变量,存储在storage区域
- student stu=student(100,"李知恩");
-
- function test1(student storage s)internal{
- student storage IU=s;//内存中的s指针通过test1(stu)后,指向了storage区域的stu对象
- IU.name="IU";//通过IU指针间接操作了storage区域的stu对象
- }
-
- function call() public returns(string){
- test1(stu);//传递的实际是指向stu对象的指针
- return stu.name;
- }//返回IU
-
- }
情形2:memory转storage
- pragma solidity ^0.4.0;
- contract structTest{
- //结构体的定义
- struct student{
- uint grade;
- string name;
- }
- //stu是状态变量,存储在storage区域
- student stu=student(10,"李知恩");
-
- function test1(student memory s)internal{
- stu=s;//将s的值赋给了stu,stu变为student(100,"IU")
- s.name="love";//修改memory上的s,不会影响storage上的stu
- }
-
- function call() public returns(uint,string){
- student memory IU=student(100,"IU");//IU是局部变量,存储在memory中
- test1(IU);//值传递,将IU的值传递给了形参s(也存储在memory当中)
- return (stu.grade,stu.name);//返回100,"IU"
- }
-
- }
情形3:storage转memory
- pragma solidity ^0.4.0;
- contract structTest{
- //结构体的定义
- struct student{
- uint grade;
- string name;
-
- }
- //stu是状态变量,存储在storage区域
- student stu=student(10,"李知恩");
-
- function test1(student storage s) pure internal returns(uint,string){
- student memory IU=s;//在memory中,s根据传递过来的stu指针,对stu对象进行了副本copy,赋值给了IU
- IU.name="IU";//在memory内的IU进行修改,不会影响存储在storage中的stu
- return(IU.grade,IU.name);
- }
-
- function call() public view returns(uint,string){
- test1(stu);//传递的是指向stu的指针
- return (stu.grade,stu.name);
- }//返回(10,"李知恩")
- //由于internal外部无法调用,因此采用这种方式在外部间接调用test1,结果说明内存中的IU的值发生了改变
- function test() public view returns(uint,string){
- return test1(stu);
- }//返回(10,"IU")
-
- }
情形4:memory转memory
- pragma solidity ^0.4.0;
- contract structTest{
- //结构体的定义
- struct student{
- uint grade;
- string name;
-
- }
- function test1(student memory s) pure internal {
- student memory IU=s;//s和IU都指向了stu的存储的memory区域
- IU.name="IU";//通过IU间接修改了stu对象
- IU.grade=18;
-
- }
-
- function call() public pure returns(uint,string){
- student memory stu=student(100,"李知恩");
- test1(stu);//memory上的对象stu,传递的是指向它的指针(这里比较特殊,属于本身对内存的一个优化操作)
- return (stu.grade,stu.name);
- }//返回(18,"IU")
- }
enum 枚举体名字{枚举1,枚举2…} 枚举1-N不能有汉字,本质上枚举1数值为0,枚举2数值为1,以此类推
枚举体主要用于状态的切换,例如从状态1切换到状态2,让代码具有可读性!
- pragma solidity ^0.4.0;
- contract enumTest{
- enum state{s1,s2,s3,s4,s5}
-
- state step=state.s1;
-
- function getEnum() public view returns(state){
- return step;
- }//返回uint8:0(也是看枚举个数,按最小标准存储)
-
- function firstStep() public returns(string){
- require(step==state.s1);//必须完成s1才能切换到s2
- step=state.s2;
- return "s1 over!";
- }
-
- function sencondStep() public returns(string){
- require(step==state.s2);//必须完成s2才能切换到s3
- step=state.s3;
- return "s1,s2 are over!";
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。