区块链学习--智能合约solidity基础语法

第一个程序 solidity编写

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1; //指定solidity的版本

// 合约
contract hello {
    string public  name;
    constructor(string memory _name) { //构造函数
            name = _name;
    }
}

在这里插入图片描述

solidity语法介绍

方法定义

solidity中使用function关键字定义一个方法,方法中包含传入参数以及返回值,方法体中实现业务方法
例如:实现从1加到100

function getSum() public view returns (uint256 ) {
        uint256 sum = 0;
        //for(init;cond;post)
        for(uint256 i = 1; i <= 100; i ++) {
            sum += i;
        }
        
        return sum;
    }
    function getSum2() public view returns (uint256 sum) {
        //for(init;cond;post)
        uint256 i = 0;
        while(i <= 100) {
            sum += i;
            i ++;
        }
        
        //return sum;
    }

数组

solidity定义数组的方式与go语言类似,使用[]来定义数组,并指定类型和长度,数组可以通过push方法添加数据。

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; //solidity<=0.8.7 && >= 0.6.0;

contract array_demo {
    string[5] public names;
    uint8[] public ages;
    
    constructor() {
        names[0] = "zhangsan";
        names[1] = "lisi";
        names[2] = "wangwu";
        
        // ages[0] = 20;
        //ages[1] = 30;
        ages.push(20);
    }
    
    function addAge(uint8 _age) public {
        ages.push(_age);
    }
    
    function getLength() public view returns (uint256, uint256) {
        return (names.length, ages.length);
    }
    
    function addName(string memory _name) public {
        names.push(_name);
    }
}

mapping定义

mapping(键值对)的定义,需要先指定键值的类型,比如:如果想用mapping存储学生的考试成绩,需要定义一个mapping,key表示学生姓名,score表示考试成绩,如下操作可以实现对数据的插入和查询

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

contract mapping_demo {
    mapping(string=>uint256) maths;
    
    function addScore(string memory _name, uint256 _score) public {
        if (maths[_name] > 0) return;
        maths[_name] = _score;
    }
    
    function getScore(string memory _name) public view returns (uint256) {
        return maths[_name];
    }
}

结构体

solidity使用struct来定义结构体,在方法中可以对结构体的各个字段进行赋值,合约部署后,直接调用setUser方法可以对人员信息进行赋值

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

struct User {
    string name;
    uint8  age;
    string sex;
}

contract struct_demo {
    User user;
    
    function setUser(string memory _name, uint8 _age, string memory _sex) public {
        user.name = _name;
        user.age  = _age;
        user.sex = _sex;
    }
    
    function getUser() public view returns (User memory) {
        return user;
    }
}

变量的存储类型,memory,storage和calldata

memory存储位置同我们普通程序的内存类似。即分配,即使用,越过作用域即不可被访问,等待被回收。而对于storage的变量,数据将永远存在于区块链上。
1.默认的函数参数,包括返回的参数,他们是memory。而默认的局部变量是storage的。

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

struct User {
    string name;
    uint8  age;
    string sex;
}

contract storage_demo {
    User adminuser;
    
    function setUser(string memory _name, uint8 _age, string memory _sex) public {
        adminuser.name = _name;
        adminuser.age  = _age;
        adminuser.sex = _sex;
    }
    
    function getUser() public view returns (User memory) {
        return adminuser;
    }
    
    function setAge1(uint8 _age) public {
        User memory user = adminuser;
        user.age = _age;
    }
    
    function setAge2(uint8 _age) public {
        User storage user = adminuser;
        user.age = _age;
    }
    
    function setAge3(User storage _user, uint8 _age) internal {
        _user.age = _age;
    }
    
    function callsetAge3(uint8 _age) public {
        setAge3(adminuser, _age);
    }
}

require的用法

require 函数用于确认条件有效性,例如输入变量,或合约状态变量是否满足条件,或验证外部合约调用返回的值
有两个参数:

  • 第一个参数为条件判断表达式,必选
  • 第二个参数为要返回的异常消息提醒,可选
    比如在充值提现过程中会判断金额是否一致,余额是否足够之类的判断
	require(_amount == msg.value, "amount must == msg.value");

完整代码:

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

contract money_demo {
    address public admin;
    address payable public user;
    uint256 totalAmount;
    
    constructor(address _owner) {
        admin = _owner;
    }
    
    function deposit(uint256 _amount) public payable {
        //if (_amount != msg.value) return;
        require(_amount == msg.value, "amount must == msg.value");
        assert(_amount > 0);
        user = payable(msg.sender);
        totalAmount = _amount;
        //address(this).balance += _amount;
    }
    
    function getBalance() public view returns (uint256, uint256) {
        //this dai biao he yue ben shen 
        // account's balance 
        return (address(this).balance, totalAmount);
    }
    
    function withdraw(uint256 _amount) public payable {
        user.transfer(_amount);
    }
}

函数修改器modifier

官方文档:modifier可以改变函数的行为。可以被继承和重写。

其实modifier被用于最多的是行为检查,这样可以使得减少检查代码的复用以及让代码看起来更简介易懂。比如,检查调用者是否有权限执行这个函数,传入的参数是否有错误等等。但是modifier不仅仅于此。通过一下一个例子来熟悉了解一下modifier的用法:

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

contract modifier_demo {
    address public admin;
    uint256 public amount;
    
    constructor() {
        admin = msg.sender;
        amount = 101;
    }
    
    modifier onlyadmin() {
        require(msg.sender == admin, "only admin can do");
        require(amount > 100, "amount must > 100");
        _;
    }
  
    function setCount(uint256 _amount) public onlyadmin {
        amount = _amount;
    }
}

上述例子中,我们通过关键字 modifier 后面接函数修改器名 onlyadmin 来定义一个modifier。在上述定义的modifier中如果调用者不是拥有者则会停止执行接下来的代码,并在控制台输出自定义的原因。如果是的话则执行到 _ 处,_ 代表使用该modifier的函数体,这里即为setCount 函数的函数体。在执行setCount 函数前先会使用onlyadmin进行检查,没有问题后才会执行。

receive函数和Fallback函数

Receive是一个接收以太币函数,一个合约中最多可以有一个 receive 函数。在对合约转账时会执行 receive 函数,例如通过 transfer()、send() 或 call()。如果 receive 函数不存在,那么 fallback 回退函数会被调用。receive 函数的
声明语法如下:
回退函数Fallback函数特点:

  • 回退函数没有 function 关键字;
  • 回退函数必须是 external 可见性,即允许被外部合约调用;
  • 如果回退函数需要接收以太币,则必须标记为 payable 关键字。
// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

contract receive_demo {
    
    uint256 totalAmount;
    address[] public addrs;
    
    receive() external payable {
        totalAmount += msg.value;
        addrs.push(msg.sender);
    }
    
    function getBalance() public view returns (uint256, uint256) {
        return (totalAmount, address(this).balance);
    }
    
    fallback() external payable {
        totalAmount += msg.value;
        addrs.push(msg.sender); 
    }
}

Fallback函数与Receive函数的区别是:Receive函数只在合约转账时调用,而Fallback函数除了可以在合约转账时调用外,在合约没有函数匹配或需要向合约发送附加数据时,也调用Fallback函数。

编写库Library

Solidity提供了Library的概念来实现代码重用,它可以被多个不同的智能合约调用。大家可以把library想象成在面向对象语言中的static类中的static函数。 Library在部署到区块链上时是很类似普通的智能合约的。这也允许大家可以使用别人部署的Library,但要十分小心的是使用非自己建立的、部署的library需要承担一定的安全风险。
比如定义比较2个字符串是否相等的库,如下

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

library libstring {
    function isEqual(string memory a, string memory b) internal pure returns (bool) {
        bytes32 hashA = keccak256(abi.encode(a));
        bytes32 hashB = keccak256(abi.encode(b));
        return hashA == hashB;
    }
}

当我调用它时,需要讲它指定某个类型

// SPDX-License-Identifier: Apache-2.0
pragma solidity^0.8.7; 

import "./libstring.sol";

contract library_demo {
    using libstring for string;
    
    function isMyEqual(string memory a, string memory b) public pure returns (bool) {
        return a.isEqual(b);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值