solidity 精简笔记

solidity 精简笔记

一、三行框架

// SPDX-License-Identifier: MIT   
pragma solidity ^0.8.0;           
contract 合约名{
    ...;
}

二、数值类型 bool、uint、int、address、bytes32

1.布尔型 bool

    // 布尔型变量
    bool public _bool = true;

2.正整数 uint、整数 int

    // 正整数、整数定义
    uint public _uint = 1; // 正整数
    uint256 public _number = 20231024; // 256位正整数
    int public _int = -1; // 整数,包括负数
    // 整数运算
    uint256 public _number2 = 2**2; // 指数
    uint256 public _number3 = 7 % 2; // 取余数
    bool public _numberbool = _number2 > _number3; // 比大小

3.地址类型 address

    // 地址定义
    address public _address = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
    address payable public _address1 = payable(_address); 
    
    // payable address,可以转账、查余额
    // balance
    uint256 public balance = _address1.balance; 
    // transfer
    address payable addr;
    addr.transfer(1);//合约向addr转账1wei
    
    address x = 0x123;
    address myAddress = this;
    if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);// 向 x 转账 10?

4.定长字节数组 bytes32

一个字节占两位,字节乘2是位数(16进制)

    // 固定长度的字节数组
    bytes32 public _byte32 = "MiniSolidity"; 
    bytes1 public _byte = _byte32[0]; //存储_byte32数组的第一个字节,即0x4d (0x是象征意义,代表十六进制)

三、函数 function、函数名(传入参数)、可见性、gas 节省支付性、returns (参数类型 参数名)

function 函数名(传入参数) 可见性 [gas 节省支付性] [returns(参数类型 参数名)]

//可见性:internal|external|public|private
//gas 节省支付性:pure|view|payable

中括号部分可省略不写。

四、函数输出

主要还是用命名式返回,直接 returns(参数类型 参数名)

    // 命名式返回
    function returnNamed() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){
        _number = 2;
        _bool = false; 
        _array = [uint256(3),2,1];
    }

五、变量存储属性(storage/memory/calldata) 与作用域分类(状态变量、局部变量、全局变量)

//变量存储属性的用法:
//变量类型 变量属性 变量名
uint[] x = [1,2,3]; //变量属性默认是storage
uint[] storage xStorage = x;
uint[] memory xMemory = x;

1.变量存储位置

  • storage 是默认属性,存在链上消耗gas
  • memorycalldata存在内存消耗gas
    • memory 的变量可修改
    • calldata的变量不可修改

2.赋值修改新变量会不会影响原变量

合约的状态变量与函数里的本地变量相互赋值时,会相互影响的情况只有两种

  1. storage赋值给storage
  2. memory赋值给memory

3.变量按作用域分类

  1. 状态变量:合约内、函数外定义

    存储在链上

    随意使用

  2. 局部变量:函数内定义

    存储在内存, gas 费低

    只能在当前函数内使用

  3. 全局变量:都是预留关键字

    随意使用

六、数组(定长、变长;length、push()、push(x)、pop() )、 结构体

    // 定长数组:变量类型[长度] 数组名
    uint[8] array1;
    bytes1[5] array2;
    address[100] array3;
    
    // 变长数组:变量类型[] 数组名
    uint[] array4;
    bytes1[] array5;
    address[] array6;
    bytes array7;    //bytes是数组,但是后面不用加[]
    
    // memory 变长数组需要定义时赋值或者 new 变量类型[](长度)
    uint[] memory array8 = new uint[](5);
    bytes memory array9 = new bytes(9);
    
    //函数传入返回数组时,需要注意位数统一,可以直接强制转换位数,例如   uint(第一个数组元素)
    [uint(1), 2, 3]
    
    //如果创建的是动态数组,则需要一个一个元素的赋值
    uint[] memory x = new uint[](3);
    x[0] = 1;
    x[1] = 3;
    x[2] = 4;
    
    //数组.成员函数    只有 length 是所有数组都有的,push()、push(x)、pop() 只在变长数组和bytes数组中才有
    //push()是末尾添一个0,push(x)是末尾添一个x,pop()是删除尾元素
    
    
    
    // 结构体
    struct Student{
        uint256 id;
        uint256 score; 
    }
     Student student; // 定义一个Student类型的变量
     
   // 结构体赋值:变量名.内部成员名 = xx;
   function initStudent2() external{
        student.id = 1;
        student.score = 80;
    }

七、映射类型 mapping

用途:通过一个人的id来查询他的钱包地址

    //mapping 映射实例
    mapping(uint => address) public idToAddress; // id映射到地址
    mapping(address => address) public swapPair; // 币对的映射,地址到地址
    
   //使用规则:
   1.自定义的结构体类型不能映射别人,只能被映射
   2.映射的存储位置只能是 storage (默认链上存储)
   3.映射声明为 public,则会获得 getter 函数
   4.新增键值对语法:_Var[_Key] = _Value
   function writeMap (uint _Key, address _Value) public{
        idToAddress[_Key] = _Value;
    }

八、变量初始值与 delete

1.值类型初始值

可以用public变量的getter函数验证注释写的初始值是否正确:

    bool public _bool; // false
    string public _string; // ""
    int public _int; // 0
    uint public _uint; // 0
    address public _address; // 0x0000000000000000000000000000000000000000

    enum ActionSet { Buy, Hold, Sell}
    ActionSet public _enum; // 第一个元素 0

    function fi() internal{} // internal空白方程 
    function fe() external{} // external空白方程 

2.引用类型初始值

可以用public变量的getter函数验证注释写的初始值是否正确:

    // Reference Types
    uint[8] public _staticArray; // 所有成员设为其默认值的静态数组[0,0,0,0,0,0,0,0]
    uint[] public _dynamicArray; // `[]`
    mapping(uint => address) public _mapping; // 所有元素都为其默认值的mapping
    // 所有成员设为其默认值的结构体 0, 0
    struct Student{
        uint256 id;
        uint256 score; 
    }
    Student public student;

3.delete 操作符

delete a 会让变量a的值变为初始值。

    // delete操作符
    bool public _bool2 = true; 
    function d() external {
        delete _bool2; // delete 会让_bool2变为默认值,false
    }

九、常数属性 constant 与 immutable

这两个常数属性的意义是节省gas的同时提升合约安全性。

immutable 更灵活,但只能作用于数值变量。

1.constant:定义时就初始化

    // constant变量必须在声明的时候初始化,之后不能改变
    uint256 constant CONSTANT_NUM = 10;
    string constant CONSTANT_STRING = "0xAA";
    bytes constant CONSTANT_BYTES = "WTF";
    address constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;

2.immutable:定义、全局变量、构造函数初始化

    // immutable变量可以在constructor里初始化,之后不能改变
    uint256 public immutable IMMUTABLE_NUM = 9999999999;
    address public immutable IMMUTABLE_ADDRESS;
    uint256 public immutable IMMUTABLE_BLOCK;
    uint256 public immutable IMMUTABLE_TEST;
    
    // 利用constructor初始化immutable变量
    constructor(){
        IMMUTABLE_ADDRESS = address(this);
        IMMUTABLE_BLOCK = block.number;
        IMMUTABLE_TEST = test();
    }
    function test() public pure returns(uint256){
        uint256 what = 9;
        return(what);
    }

十、控制流(if、for、while、?:),用solidity实现插入排序

//if-else
function ifElseTest(uint256 _number) public pure returns(bool){
    if(_number == 0){
    return(true);
    }
    else{
    return(false);
    }
}

//for
function forLoopTest() public pure returns(uint256){
    uint sum = 0;
    for(uint i = 0; i < 10; i++){
    sum += i;
    }
    return(sum);
}

//while
function whileTest() public pure returns(uint256){
    uint sum = 0;
    uint i = 0;
    while(i < 10){
    sum += i;
    i++;
    }
    return(sum);
}

//?:(条件? 条件为真的输出:条件为假的输出)
function ternaryTest(uint256 x, uint256 y) public pure returns(uint256){
    // return the max of x and y
    return x >= y ? x: y; 
}

十一、构造函数 constructor 和修饰器 modifier

1.构造函数 constructor:部署地址

   //初始化合约的 owner 地址
   address owner; // 定义owner变量

   // 构造函数
   constructor() {
      owner = msg.sender; // 在部署合约的时候,将owner设置为部署者的地址
   }

2.修饰器 modifier:检查地址控制合约权限

十二、事件 event

Solidity中的事件(event)是EVM上日志的抽象,它具有响应和经济两个特点:

  • 响应:应用程序(ether.js)可以通过RPC接口订阅和监听这些事件,并在前端做响应。
  • 经济:链上存储数据比存储事件的成本高。事件是EVM上比较经济的存储数据的方式,每个大概消耗2,000 gas;相比之下,链上存储一个新变量至少需要20,000 gas

可以使用emit关键字来释放一个事件。

十三、继承:简单继承、多重继承以及修饰器(modifier)和构造函数(constructor)的继承

//多重继承:is , , , ...
contract Erzi is Yeye, Baba{
    // 继承两个function: hip()和pop(),输出值为Erzi。
    function hip() public virtual override(Yeye, Baba){
        emit Log("Erzi");
    }

    function pop() public virtual override(Yeye, Baba) {
        emit Log("Erzi");
    }
    
    //调用父合约中的函数:
    //父合约名.函数名()
    function callParent() public{
        Yeye.pop();
    }
    //super.函数名()
        function callParentSuper() public{
        // 将调用最近的父合约函数,Baba.pop()
        super.pop();
    }

十四、抽象合约 abstract 与接口 interface

1.抽象合约:有未实现的函数

//合约 contract 前面加上 abstract,未实现的函数 属性要加上 virtual ,并且以 ; 结尾
abstract contract InsertionSort{
    function insertionSort(uint[] memory a) public pure virtual returns(uint[] memory);
}

2.接口:定义合约功能,以及如何触发它们

接口类似于抽象合约,但它不实现任何功能。接口是智能合约的骨架,定义了合约的功能以及如何触发它们。

十五、异常:error、require 与 assert

写智能合约经常会出bugsolidity中的异常命令可以帮助我们debug

首选 error 搭配 revert。

猜你喜欢

转载自blog.csdn.net/qq_42465670/article/details/130931043