DAPP开发(四)——Solidity语法

整型uint 和 int

uint 是默认指uint256,只能是非负的整数,以太坊严格规范,金额类型的数据都使用uint

int 默认是int256,可正可负。

uint和int之间不能相互转化

对于智能合约一定要合理安排整数类型声明,防止整数溢出的问题。


固定长度bytes类型

和uint是一样的,bytes默认是bytes1,byte1相当于uint8,bytes可以从1写到bytes32,bytes32其实就是uint256,它的长度其实就是对应的后缀数字,1-32,以一增加,但是其长度属性是不可以修改的。

动态长度bytes类型

定义方式需要bytes对象

bytes name = new bytes(2) //定义一个长度为2的bytes类型

可以修改每个值,也可以修改长度,或通过数组的push方法也可以改变长度

name[0] = 0x7a
name[1] = 0x88
name.length=5
name.push(0x99)

bytes类型一般用于十六进制的数据存储,固定长度bytes数据可以进行长度的转换,通过bytes1,截取长度为1,bytes2截取长度为2,如果截取长度大于该bytes字节的长度,那么补0。

bytes name = 0x7a68
bytes1(name) //0x7a
bytes2(name) //0x7a68
bytes3(name) //0x7a6800

固定长度bytes数据可以转动态长度字节数组,通过new bytes(bytes)的方式,然后创建一个新的动态长度bytes对象,通过for循环的形式将每个字节添加到新的bytes对象即可。

bytes2 name = 0x7a68
bytes newName = new bytes(name.length)
for(uint i;i<name.length;i++){
    newName[i] = name[i]
}

 string类型

string类型不能直接获取长度,必须通过转为bytes类型后才可以,通过bytes的[index]获取内容,获取到的是十六进制的数据,修改单个字节也是通过bytes类型。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Demo{
    string name = "name";
    function getLength() view public returns (uint){
        return bytes(name).length;
    }
    function getName() view public returns (bytes memory){
        return bytes(name);
    }
    function changeName() public returns (string memory){
        bytes(name)[0] = 'L';
        return name;
    }
}

如果name为汉字,那么所一个汉字占三个,特殊字符占一个字节。 

动态长度bytes转string:

bytes name = new Bytes(2);
name[0] = 0x7a;
name[1] = 0x68;
function transfer() public view returns(string){
    return string(name);
}

固定长度bytes转string:分两步,固定长度bytes转为动态长度bytes,将动态长度bytes转为string

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Transfer{
    bytes2 name = 0x7a68;
    function changeToDynamic() public returns (string memory){
        bytes memory newName = new bytes(name.length);
        //转为动态数组
        for(uint i=0;i<name.length;i++){
            newName[i] = name[i];
        }
        return this.transferTostring(newName);
    }
    function transferTostring(bytes memory  _name) public returns (string memory){
        return string(_name); //动态长度字节转为字符串
    }
}

固定数组

可以获取长度,但是长度length是不可以改变的

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Array{
    uint [5] arr = [1,2,3,4,5];

    function Init () public{
        arr[0] = 1;
        arr[1] = 100;
    }
    
}

动态数组:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Array{
    uint [] arr = [1,2,3,4,5];
    function Init () public{
        arr[0] = 1;
        arr[1] = 100;
    }
    function getArray() view  public returns (uint [] memory){
        return arr;
    }
    function changeLength() public {
        arr.push(); //添加长度
    }
    function changeLength2() public {
        arr.pop(); //减少数组长度
    }
}

固定长度二维数组

定义语法法与其他语言有区别,一维数组的长度取决于后一个长度参数,二维长度取决于第一个参数,但是获取时和其他的一致,下面固定长度的也不能修改长度:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract TwoArray {
    uint256[2][3] arr = [[1, 2], [3, 4], [5, 6]];

    function add() view public returns (uint256) {
        uint256 sum=0;
        for (uint256 i = 0; i < arr.length; i++) {
            for (uint256 j = 0; j < arr[0].length; j++) {
                sum += arr[i][j];
            }
        }
        return sum;
    }
    function change() public returns (uint256 [2][3] memory) {
        for (uint256 i = 0; i < arr.length; i++) {
            for (uint256 j = 0; j < arr[0].length; j++) {
               arr[i][j]=4;
            }
        }
        return arr;
    }
}

 动态长度二维数组

可修改长度。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract TwoArray {
    uint256[][] arr = [[1, 2], [3, 4], [5, 6]];

    function add() public view returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < arr.length; i++) {
            for (uint256 j = 0; j < arr[0].length; j++) {
                sum += arr[i][j];//求和
            }
        }
        return sum;
    }

    function change() public returns (uint256[][] memory) {
        for (uint256 i = 0; i < arr.length; i++) {
            for (uint256 j = 0; j < arr[0].length; j++) {
                arr[i][j] = 4; //改值
            }
        }
        return arr;
    }

    function getData() public view returns (uint256[][] memory) {
        return arr;
    }
    //修改长度
    function changeLength() public returns (uint256[][] memory) {
        arr[0].push(3); 
        arr[1].pop();
        return arr;
    }
}

数组字面量:

不可以修改数组的内容以及长度 。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Array{
    function getArray() pure public returns ( uint8[3] memory){
        return [1,2,3];
    }
    function getArray2() pure public returns ( uint[3] memory){
        return [uint(1),2,3];
    }
}

上图使用字面量的形式返回数组,在定义数组时,uint会默认最小匹配原则,从uint8开始,如果存储数据超过255,则使用uint256,所以在上述function的返回值中,使用uint8数据类型。第二种方式可以指定存储数据的类型,给数组第一个元素添加即可,剩下的元素则默认为uint数据,此时默认是uint256。

address类型

在比特币的网络中是没有账户地址的概念,但在以太坊中是有的,包括合约账户地址和外部账户地址,是一串16进制的数据字符串。address是通过uint160进行存储的,两种类型可以相互强制转化,地址之间是可以进行比较大小的。

address account = 0x4D26100f60525C5Ef35DA5B4dFc7B80d55050574

uint160 num = uint160(account)

address addr = address(num)

payable,支付功能(remix调试)

 函数中需要使用payable关键字,我们可以通过这个函数给合约地址转账,这里的金额为wei的单位。可以看到当前的this其实就是当前合约的地址,既然我们可以通过this.balance获取余额,那么我们也可以使用地址来获取不同账户的余额。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract PayTest{
    function pay() payable  public {

    }
    function getBalance() public view returns(uint){
        return address(this).balance;
    }
    function geThis() public view returns(address){
        return address(this);
    }
    function getOtherBalance(address account) public view returns(uint){
        return account.balance;
    }
}

 给不同的账户进行转账

function transfer() public payable {
        address account = 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB;//其他的账户
        payable (account).transfer(msg.value);
    }

如果此transfer函数函数内部函数体为空,那么就会默认转到当前的合约账户,同时也可以修改为有参数的函数,不使用msg.value。如果出现msg.value的以太币数量大于代码里转账的以太币数量,那么多余的数量会直接转至当前合约账户。

常用全局变量

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Global{
   function getDlobal() public view returns (address){
       return msg.sender;
   }
}

msg.sender(address):合约调用者账户地址。

msg.data(bytes):完整的调用数据。

msg.sender(address):当前调用发起人的地址。

msg.value(address):这个消息所携带的以太币,单位是wei。

block.coinbase(address):当前矿工地址。

block.difficulty(uint):当前矿的难度。

block.number(uint):当前区块号。

block.timestamp(uint):时间戳。

now(uint):当前块的时间戳。

tx.gasprice(uint):交易的gas价格。

tx.origin(address):交易的发送者。


send函数

function send() public payable returns(bool){
        address account = 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB;
        return payable (account).send(msg.value);
    }

一般不用,底层函数会有点问题,有时候出现问题也不会报错,与transfer的用法一样。

调用递归深度不能超过1024,如果gas不够会执行失败,使用这个方法要检查结果是否成功,transfer相对比较安全。

mapping 映射

一对一的映射关系,一个mappig对象可以有多个数据,但是必须遵循相应的映射关系。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Mapping{
    mapping(address => uint) id;
    mapping( uint => string) name;
    uint sum = 0;

    function register(string memory _name) public {
        sum++;
        id[msg.sender] = sum;
        name[sum] = _name;
    }
    function getId(address _address) public view  returns (uint){
        return id[_address];
    }
    function getName(uint _id) public view returns (string memory){
        return name[_id];
    }
}

函数

遵循以下模版条件

function  funName(paramType paramName) { public | internal | external | public} [pure | constant | view | payable] [ returns (type) ] 

重载:函数名相同,传入参数不同会有不同的功能,不考虑函数返回值是否相同。但是要注意如果参数类型为uint以及uint8,如果传参255以内的数据,会出现报错的情况,因为两者都包含对应的数据,如果传参256就不会报错了,uint8的最大值就是255。

还有个特殊的类型,uint160和address类型本质是一样的,所以这两个无论何时报错的。不可以作为判断的条件

function test(address _address) public{}
function test(uint160 _id) public{}

function test2(uint id) public{}
function test2(uint8 id) public{}

函数传参

在进行传参时,可以正常传参,也可以以对象的形式传参(可以不考虑传参的顺序),在直接调用时可以只传一个参数(函数设置两个参数),但是如果在其他函数中调用时,必须严格遵守传入所有的参数。

函数返回值

返回值要有数据类型,同时可以有参数名称,也可以没有,有个小技巧,修改函数参数不用return。

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract Return{
    function mul() public pure returns(uint num){
        num = 100;
    }
    function mul2() public pure returns(uint num){
        num = 100;
        return 10
    }
    function getResult(uint a,uint b) public pure returns(uint add,uint x){
        add = a+b;
        x = a*b;
    }
}

如果Return和参数修改都存在的话,以Return的值为准,同时可以返回多个参数,可以进行简化:

function getResult(uint a,uint b) public pure returns(uint add,uint x){
        return (a+b,a*b)
    }

可以用于值的交换。

作用域

同一作用域中不能重复定义相同变量,遵循作用域和作用域规则。

权限修饰

public,internal,external函数可以被继承,private只能合约内部使用,不能被继承,外部不能被调用。

public在合约的内部外部,子合约都可以调用。

internal不能被外部调用,但是可以在合约内部以及子合约的内部使用。

external:只能在合约外部调用,继承的合约内部也不可以调用。但也可以通过this来调用,在这里是通过地址来调用,原理也是通过外部的形式调用。

在new关键字下创建的合约对象也可以使用external方法。

继承:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;

contract father{
    function test() public pure returns(string memory){
        return "Father";
    }
}


contract son is father{
    function oops() public pure returns(string memory){
        return test();
    }
}

contract Test{
    father f =new father();
    function opt() public view returns(string memory){
        return f.test();
    }
}

猜你喜欢

转载自blog.csdn.net/m0_59962790/article/details/130782980
今日推荐