solidity学习(day1)持续更新

Type:

整数

int public _int =-1

uint public _uint =1

uint256 public _number =20220330 //256位整数

//地址

address(存储20字节) public _address=0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;

address payable public _address1 = payable(_address); // payable address,可以转账、查余额

// 地址类型的成员

uint256 public balance = _address1.balance; // balance of address

定长字节数组(数值类型)

bytes32 public _byte32 ="MiniSolidity";

bytes1 public  _byte=_byte32[0]

不定长字节数组(引用类型)

//枚举(enum)

enum ActionSet {Buy,Hold,Sell}

//创建enum action

ActionSet action=ActionSet.Buy;

//枚举可以显式地和uint相互转换

函数权限关键字

pure:既不能读也不能写入链上状态变量

view:可以读但不能写入

internal 和external

可以通过external类型的函数间接调用internal类型的函数

返回值

命名式返回 public pure returns(uint256 _number, bool _bool, uint256[3] memory _array)

读取所有返回值

uint256 _number;

bool _bool;

uint256[3] memory _array;

(_number, _bool, _array) = returnNamed();

部分返回值

(,_bool,)=returnNamed();

数据位置

  1. storage:合约里的状态变量默认都是storage,存储在链上。

  2. memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。

  3. calldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改(immutable),一般用于函数的参数。

  • storage(合约的状态变量)赋值给本地storage(函数里的)时候,会创建引用,改变新变量会影响原变量。

  • 其他情况下,赋值创建的是本体的副本,即对二者之一的修改,并不会同步到另一方

变量的作用域

Solidity中变量按作用域划分有三种,分别是状态变量(state variable),局部变量(local variable)和全局变量(global variable)

状态变量:存储在链上的数据 例如uint public x=1;

局部变量: 局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存储在内存里,不上链,gas低。局部变量在函数内声明

例如:uint xx=1

全局变量:是全局范围工作的变量,都是solidity预留关键字。他们可以在函数内不声明直接使用:例如:address sender = msg.sender;

以太单位:

Solidity中不存在小数点,以0代替为小数点,来确保交易的精确度,并且防止精度的损失,利用以太单位可以避免误算的问题,方便程序员在合约中处理货币交易。

1 wei=1

1 gwei =1e9=1000000000

1 ether=1e18=10000000000000000000

时间单位:

  • seconds: 1

  • minutes: 60 seconds = 60

  • hours: 60 minutes = 3600

  • days: 24 hours = 86400

  • weeks: 7 days = 604800

数组 array

数组(Array)是solidity常用的一种变量类型,用来存储一组数据(整数,字节,地址等等)。数组分为固定长度数组和可变长度数组两种:

  • 固定长度数组:在声明时指定数组的长度。用T[k]的格式声明,其中T是元素的类型,k是长度,例如:

  • 固定长度 Array

  •    uint[8] array1;

  •    bytes1[5] array2;

  •    address[100] array3;

可变长度数组(动态数组):在声明时不指定数组的长度。用T[]的格式声明,其中T是元素的类型,例如:

可变长度 Array

   uint[] array4;

   bytes1[] array5;

   address[] array6;

  bytes array7;

//例子1

uint[5] arr = [0,1,2,3,4];//创建一个定长的数组

    uint[] storageArr;

    function a() public {

//通过索引查询时要先初始化

        uint[5] memory arr1 = [uint(0),1,2,3,4];//uint8显示的转换为uint256,否则会报类型错误。

        uint[] memory memoryArr;

        //storageArr[0] = 12;

        //memoryArr[0] = 13; //执行会报VM error: invalid opcode.,原因是数组还没有执行初始化。

        storageArr = new uint[](5);

        memoryArr = new uint[](5);

        storageArr[0] = 12;

        memoryArr[0] = 13;

    }

2、存储位置对赋值的影响:

值类型申明不允许指定storage/memory,值类型之间赋值都是创建拷贝。

下面指引用类型赋值操作:

Storage与memory相互赋值,会创建拷贝。

storage/memory同一存储区域内的引用类型(除状态变量)之间赋值不会创建拷贝,创建引用;所有变量给Storage状态变量赋值,都会创建拷贝。

Storage状态赋值给Storage局部变量:不创建拷贝,仅创建一个引用。

Memory引用类型赋值给Memory引用类型:不创建拷贝,仅创建一个引用。

memory变量不能给storage局部变量赋值,但可以给storage状态变量赋值。

bytes比较特殊是数组,但不用写[],声明单字节数组用bytes[]或bytes但是bytes1更省gas

//memory动态数组

uint[] memory array8 =new uint[](5)

bytes memory array9=new bytes(9)

用new操作符来创建,但是必须声明长度,并且声明后长度不能改变。

数组成员

  • length: 数组有一个包含元素数量的length成员,memory数组的长度在创建后是固定的。

  • push(): 动态数组拥有push()成员,可以在数组最后添加一个0元素,并返回该元素的引用。

  • push(x): 动态数组拥有push(x)成员,可以在数组最后添加一个x元素。

  • pop(): 动态数组拥有pop()成员,可以移除数组最后一个元素。

  • push:

  • 1.面对uint[], push可以加一个uint

  • 2.面对bytes[],push只可以加256以内的(2的8次方)

  • push返回的数组长度

结构体 struct

Solidity支持通过构造结构体的形式定义新的类型。结构体中的元素可以是原始类型,也可以是引用类型;结构体可以作为数组或映射的元素。创建结构体的方法:

struct Student{

uint256 id;

uint256 score;

}

Student student;//初始一个student结构体

//给结构体赋值的四种方法

在函数中创建一个storage的struct引用

function initStudent1() external{

Student storage _student =student //这里面定义的_student会指向student,更改里面的外面也会修改

_student.id=11;

_student.score=100; }

//方法2:直接俄引用状态变量的struct

function initStudent2( ) external{

student.id=1;

student.sscore=80;z

}

//方法3:构造函数

function initStudent3() external{

student =Student(3,90);

}

//方法4:key value

function initStudent4() external{

student=Student({id :4,score:60});

}

//映射Mapping( 哈希表)将数组的数字下标转化为key下标,映射不能用结构体

mapping(uint =>address) public idToAddress ;//id映射到地址

mapping  (address =>address) public swapPair ;//币对的映射,地址到地址

映射实质上就是 代币迁移

在旧币钱包和新币钱包之间建立一个对应关系

  • 规则2:映射的存储位置必须是storage,因此可以用于合约的状态变量,函数中的storage变量,和library函数的参数(见例子)。不能用于public函数的参数或返回结果中,因为mapping记录的是一种关系 (key - value pair)。

  • 规则3:如果映射声明为public,那么Solidity会自动给你创建一个getter函数,可以通过Key来查询对应的Value。

  • 规则4:给映射新增的键值对的语法为_Var[_Key] = _Value,其中_Var是映射变量名,_Key和_Value对应新增的键值对。

映射的原理

  • 原理1: 映射不储存任何键(Key)的资讯,也没有length的资讯。

  • 原理2: 映射使用keccak256(abi.encodePacked(key, slot))当成offset存取value,其中slot是映射变量定义所在的插槽位置。

  • 原理3: 因为Ethereum会定义所有未使用的空间为0,所以未赋值(Value)的键(Key)初始值都是各个type的默认值,如uint的默认值是0。

constant和immutable

只有数值变量可以声明constant和immutable

状态变量声明这个两个关键字之后,不能在合约后更改数值。这样做的好处是提升合约的安全性并节省gas。

//constant变量必须在声明时或构造函数中初始化

uint256 constant CONSTANT_NUM=10;

string constant CONSTANT_STRING = "0xAA";

bytes constant CONSTANT_BYTES = "WTF";

address constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;

immutable变量可以在声明时或构造函数中初始化,因此更加灵活。

// immutable变量可以在constructor里初始化,之后不能改变

    uint256 public immutable IMMUTABLE_NUM = 9999999999;

    address public immutable IMMUTABLE_ADDRESS;

    uint256 public immutable IMMUTABLE_BLOCK;

    uint256 public immutable IMMUTABLE_TEST;

你可以使用全局变量例如address(this),block.number ,或者自定义的函数给immutable变量初始化。在下面这个例子,我们利用了test()函数给IMMUTABLE_TEST初始化为9:

address public immutable immutable_address;

uint256 public immutable immutable_block;

constructor(){

immutablle_address=address(this);

immutable_block =block.number;

immutable_test=test();

}

function test() public pure returns(uint256){

uint256 what=9;

return(what);

}

构造函数

构造函数(constructor)是一种特殊的函数,每个合约可以定义一个,并在部署合约的时候自动运行一次。它可以用来初始化合约的一些参数,例如初始化合约的owner地址:

老写法

constructor(){

}

//新写法

address owner /.地址

function 合约名 () public{

owner =msg.sender

}

修饰器

修饰器(modifier)是solidity特有的语法,类似于面向对象编程中的decorator,声明函数拥有的特性,并减少代码冗余。它就像钢铁侠的智能盔甲,穿上它的函数会带有某些特定的行为。modifier的主要使用场景是运行函数前的检查,例如地址,变量,余额等。

(类似于vue的过滤器,对数据进行筛选

modifier onlyOwner{

require(msg.sender ==owner);//检查调用者是否为owner,

//require作用是如果值为true则执行下面的语句

_;//如果是的话继续运行函数主体;否则报错并revert交易

}

//判断是否以owner用户登录

//带有onlyOwner修饰符的函数只能owner调用

function changeOwner(address _newOwner)external onlyOwner{ //修改owner,类似于修改密码

owner =_newOwner;

}

事件

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

  • 响应:应用程序(ethers.js)可以通过RPC接口订阅和监听这些事件,并在前端做响应。

  • 经济:事件是EVM上比较经济的存储数据的方式,每个大概消耗2,000 gas;相比之下,链上存储一个新变量至少需要20,000 gas。

声明事件

事件的声明由event关键字开头,接着是事件名称,括号里面写好事件需要记录的变量类型和变量名。以ERC20代币合约的Transfer事件为例:

event Transfer(address indexed from, address indexed to, uint256 value);

我们可以看到,Transfer事件共记录了3个变量from,to和value,分别对应代币的转账地址,接收地址和转账数量,其中from和to前面带有indexed关键字,他们会保存在以太坊虚拟机日志的topics中,方便之后检索。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值