布尔(bool): 可能的取值为字符常量值true或false
整型(int/uint): 分别表示有符号和无符号的不同位数的整型变量;支持关键字uint8到uint256(无符号,从8位到256位)以及int8到int256,以8位为步长递增
·定长浮点型(fixed/ufixed): 表示各种大小的有符号和无符号的定长浮点型;在关键字 ufixedMxN和fixedMxN中,M表示该类型占用的位数,N表示可用的小数位数
·地址(address): 存储一个20字节的值(以太坊地址大小)
·定长字节数组: 关键字有bytes1,bytes2,bytes3,…,bytes32
·枚举(enum): 一种用户可以定义类型的方法,与C语言类似,默认从0开始递增,一般用来模拟合约的状态 .枚举类型用来用户自定义一组常量值 。
pragma solidity >=0.4.0 <0.6.0;
contract Purchase {
enum State {
Created, Locked, Inactive
}
**·函数(function)😗*一种表示函数的类型
Solidity的引用类型数组(Array)
·数组可以在声明时指定长度(定长数组),也可以动态调整大小(变长数组、动态数组)
· 对于存储型(storage)的数组来说,元素类型可以是任意的(即元素也可以是数组类型,映射类型或者结构体);
· 对于内存型(memory)的数组来说,元素类型不能是映射(mapping)类型
·固定大小k和元素类型T的数组被写为T[k],动态大小的数组 为T[]。例如,一个由5个uint动态数组组成的数组是uint[][5
·要访问第三个动态数组中的第二个uint,可以使用x[2][1] 。越界访问数组,会导致调用失败回退
·如果要添加新元素,则必须使用push()或将length增大·
变长的storage数组和bytes(不包括string)有一个push()方 法。可以将一个新元素附加到数组末端,返回值为当前长度
pragma solidity>=0.4.16<0.6.0;
contract C{
function f(uint len) public pure {
uint[] memorya =newuint[](7);
bytes memory b=new bytes(len);
assert(a.length ==7);
assert(b.length == len);
a[6]=8;
}
结构(Struct)
Solidity支持通过构造结构体的形式定义新的类型
映射(Mapping)
映射可以视作哈希表,在实际的初始化过程中创建每个可能的key,并将其映射到字节形式全是零的值(类型默认值)
eg:声明一个映射:mapping(_KeyType=>_ValueType)
·KeyType可以是任何基本类型。这意味着它可以是任何内置值类型加上字节和字符串。不允许使用用户定义的或复杂的类型,如枚举,映射,结构以及除bytes和string之外的任何数组类型。
·ValueType可以是任何类型,包括映射。
pragma solidity >=0.4.0 <0.6.0;
contract MappingExample{
mapping(address => uint) public balances;
function update(uint newBalance) public {
balances[msg.sender] =newBalance;
}
}
contract MappingUser {
function f() public returns (uint) {
MappingExample m=new MappingExample();
m.update(100);
//因为balances 为public的,所以等于是内置的balances 一个方法,取值的时候就用m.balances(),不用m.balances[]
return m.balances(address(this));
}
}
Solidity的地址类型
address
地址类型存储一个20字节的值(以太坊地址的大小);地址类型也有成员变量,并作为所有合约的基础
address payable(v0.5.0引入)
与地址类型基本相同,不过多出了transfer和send两个成员变量
两者区别和转换
Pavable地址是可以发送ether的地址,而普通address不能
允许从payable address到address的隐式转换,而反过来的直接转换是不可能的(唯一方法是通过uint160来进行中间转换)
从0.5.0版本起,合约不再是从地址类型派生而来,但如果它有payable的回退函数,那同样可以显式转换为 address 或者 address payable类型
balance和transfer
可以使用balance属性来查询一个地址的余额,可以使用transfer函数,向一个payable地址发送以太币Ether(以wei为单位)
address payable x= address(0x123);
address myAddress = address(this);
if (x.balance < 10 && myAddress.balance >= 10)
x.transfer(10);
send
send是transfer的低级版本。如果执行失败,当前的合约不会因为异常
而终止,但 send会返回false
call
也可以用call来实现转币的 *** 作,通过添加gas()和value()修饰器:
nameReg.call.gas(1000000).value(1ether)(
abi.encodeWithSignature("register(string)","MyName"));
Solidity数据位置
· 所有的复杂类型,即数组、结构和映射类型,都有一个额外属性,“数据位置”,用来说明数据是保存在内存memory中还是存储
storage
·根据上下文不同,大多数时候数据有默认的位置,但也可以通过在类型名后增加关键字storage或memory进行修改
·函数参数(包括返回的参数)的数据位置默认是memory,局部变量的数据位置默认是storage,状态变量的数据位置强制是storage
·另外还存在第三种数据位置,calldata,这是一块只读的,且不会永
久存储的位置,用来存储函数参数。外部函数的参数(非返回参数)
的数据位置被强制指定为calldata,效果跟memory差不多
总结:
强制指定的数据位置
> 外部函数的参数(不包括返回参数):calldata;
> 状态变量::storage
默认数据位置
函数参数(包括返回参数):memory;
引用类型的局部变量: storage
值类型的局部变量:栈(stack)
特别要求
公开可见(publiclyvisible)的函数参数一定是memory类型,如果要求是storage类型则必须是private或者internal函数,这是为了防止随意的公开调用占用资源
eg:
memory不能push *** 作,必须是storage
storage类型不允许公开,只能自己调,将public设置为internal
函数的可见性可以指定为external,public,internal或者private;对于状态变量,不能设置为external,默认是internal。
external:
外部函数作为合约接口的一部分,意味着我们可以从其他合约和交易中调用。一个外部函数f不能从内部调用(即f不起作用,但this.f()可以)。当收到大量数据的时候,外部函数有时候会更有效率。
public:
public函数是合约接口的一部分,可以在内部或通过消息调用。对于public状态变量,会自动生成一个getter函数。
internal:
这些函数和状态变量只能是内部访问(即从当前合约内部或从它派生的合约访问),不使用 this 调用。
private:
private函数和状态变量仅在当前定义它们的合约中使用,并且不能被派生合约使用。
**· pure:**纯函数,不允许修改或访问状态
**·view:**不允许修改状态
**·payable:**允许从消息调用中接收以太币Ether。
·constant:与view相同,一般只修饰状态变量,不允许赋值(除初始化以外)
·使用修饰器modifier可以轻松改变函数的行为。例如,它们可以在执行函数之前自动检查某个条件。
·修饰器modifier是合约的可继承属性,并可能被派生合约覆盖。
·如果同一个函数有多个修饰器modifier,它们之间以空格隔开,修饰
器modifier会依次检查执行。
·回退函数(fallbackfunction)是合约中的特殊函数;没有名字,不能有参数也不能有返回值
·如果在一个到合约的调用中,没有其他函数与给定的函数标识符匹配(或没有提供调用数据),那么这个函数(fallback函数)会被执行
· 每当合约收到以太币(没有任何数据),回退函数就会执行。此外,为了接收以太币,fallback函数必须标记为payable。如果不存在这样
的函数,则合约不能通过常规交易接收以太币
·在上下文中通常只有很少的gas可以用来完成回退函数的调用,所以
使fallback 函数的调用尽量廉价很重要
· 事件是以太坊EVM提供的一种日志基础设施。事件可以用来做 *** 作记录,存储为日志。也可以用来实现一些交互功能,比如通知UI,返回函数调用结果等
· 当定义的事件触发时,我们可以将事件存储到EVM的交易日志中,日志是区块链中的一种特殊数据结构:日志与合约关联,与合约的存储
合并存入区块链中;只要某个区块可以访问,其相关的日志就可以访问;但在合约中,我们不能直接访问日志和事件数据
·可以通过日志实现简单支付验证SPV(Simplified PaymentVerification),如果一个外部实体提供了一个带有这种证明的合约,它可以检查日志是否真实存在于区块链中
Solidity使用“状态恢复异常”来处理异常。这样的异常将撤消对当前调用(及其所有子调用)中的状态所做的所有更改,并且向调用者返回错误。
函数assert和reguire可用于判断条件,并在不满足条件时抛出异常
·assert()一般只应用于测试内部错误,并检查常量
·require()应用于确保满足有效条件(如输入或合约状态变量),或验证调用外部合约的返回值
·revert()用于抛出异常,它可以标记一个错误并将当前调用回退
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)