div#pop_ad { opacity: 0; }
AD
首页 > 数字货币 > 正文

「链块技术38期」以太坊智能合约-Solidity变量类型:值类型 上

[2021-01-29 08:19:58] 来源: 编辑:wangjia 点击量:
评论 点击收藏
导读: 原文链接:http://www.liankuai.tech/public/technology/71.html区块链技术教程——智能合约,本文主要讲解了区块链开发技术——以太坊智能合约语言Solid
原文链接:http://www.liankuai.tech/public/technology/71.html

区块链技术教程——智能合约,本文主要讲解了区块链开发技术——以太坊智能合约语言Solidity 值类型变量的一些特征和使用方法。

一、目录

☛值类型和引用类型的区别

☛布尔类型(bool)

☛整型(int、uint)

☛定点型小数(fixed、ufixed)

☛地址类型(address)


☛定长字节数组(bytes1,bytes2,bytes3,...,bytes32)

☛有理数和整数字面量

☛地址字面量

☛字符串字面量

☛十六进制字面量(hex)

☛枚举类型(enum)


二. 值类型和引用类型的区别
Solidity变量类型分为两大类——值类型、引用类型

值类型:变量的存储空间存的是变量的数据

引用类型:变量的存储空间存的是变量数据所在的存储空间的地址

注意:值传递和引用传递。值类型的变量,赋值是简单的值传递,即两个变量占有独立的存储区域。引用类型赋值传递的是变量的引用,即两个变量指向同一存储区域

三. 值类型——布尔 (bool)
bool: 只有两种值true和false(默认false)。

3.1 支持的运算符:
! 逻辑非 逻辑与|| 逻辑或== 等于!= 不等于
3.2 实例:
bool a = true;bool b = !a;// a == b - false// a != b - true// a || b - true// a b - false

逻辑与( )和逻辑或(||)都遵循短路原则,即如果根据前一个表达式可以得到运算结果,则不会执行后面的表达式

四. 值类型——整型(int/uint)int(m):有符号整数uint(m):无符号整数m关键字取值为8~256步幅是8 ,表示在内存中2进制的位数,控制了整数的取值范围,不写默认为256。uint和int分别是uint256和int256的别名。m一定要是8的整数倍
4.1 操作
比较: =, ,==,!=, =, (结果为bool)位操作符: ,|,^(按位异或),~(按位取反)算术运算符:+, - ,一元 - ,一元 +,*,/,%(取余),**(幂), (左移), (右移)

注意
除法总是截断,但如果两个运算符都是常量(或常量表达式),则它不会截断。除零和取余有零引发异常。左移几位和右移几位相当于乘以或者除以2的几次方,如果参数为负数的话会引发异常。在Solidity中不支持八进制。
五. 值类型——定点数(Fixed Point Numbers)
5.1 定点小数

到现在为止还没有被solidity完全支持,可以被声明,不能被赋值也不能用定点数赋值fixed/ufixed 各种大小的有符号和无符号定点小数,ufixedMxN and fixedMxN关键字M代表定点数占用的二进制位数,N代表定点数能表示多少位小数,M必须是8-256之间的,以8为步幅的整数,N必须是0-80之间的整数,ufixed 和fixed 默认为ufixed128x18和fixed128x18
比较运算: =, , ==, !=, =, (结果为bool)算数运算: +, -, 一元-, 一元 +, *, /, % 取余
六. 值类型——地址类型(address)
在了解地址之前需要知道一个名词---ABI协议:

Application Binary Interface 应用二进制接口,是从区块链外部与合约进行交互以及合约与合约间进行交互的一种标准方式。ABI是以太坊的一种合约间调用时的一个消息格式。类似Webservice里的SOAP(Simple Object Access Protocol简单对象访问协议)协议一样。

常见格式:
[ { "constant": false, "inputs": [ { "name": "index", "type": "uint8" }, { "name": "s", "type": "string" } ], "name": "removeItem", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }]

地址:保存一个20字节值,使用40位16进制数表示。地址类型也有成员,并作为所有合约的基础。

6.1 地址成员:
以wei位单位返回该地址的余额
 address .balance(uint256)
从当前合约地址中给调用函数的地址账户转入amounts数量(以wei为单位)的金额,即从当前合约转账到某账户地址。如果执行失败,将抛出异常,需要支付2300gas的费用,不可以调整。
 address .transfer(uint256 amount)

其中address就是要把合约中的币转到哪个账号地址。

范例:
pragma solidity ^0.4.24;contract AddressExample { //定义一个接受以太币的函数往合约里充值 function AddressExample() payable{} //函数的参数分别是划转到某账号地址以及转账数量 function giveEthersTo(address _toAccount,uint amount){ if (this.balance =amount){ _toAccount.transfer(amount); } } function getBalance() view returns(uint){ return this.balance; } //定义一个匿名的回退函数接收异常情况下退回的以太币 function() payable{}}
如果合约地址调用transfer,那么需要合约地址有payable类型的回退函数,并且会随着转账一块执行回退函数中的代码,如果因为回退函数中的代码执行把gas消耗光了,EVM会抛出异常,转账也会被回退。send是低级对等的转账。执行失败,不会抛出异常,会返回false,需要支付2300gas的费用,不可以调整。推荐使用transfer而不使用send
 address .send(uint256 amount) returns (bool)
call(), callcode() 和 delegatecall() 函数
 address .call(...) returns (bool) address .callcode(...) returns (bool) address .calldelegate(...) returns (bool)

为了和非ABI协议;也就是定义操作函数签名,参数编码,返回结果编码等的合约进行交互,可以使用call() 函数, 它用来向另一个合约发送原始数据,支持任何类型任意数量的参数,每个参数会按规则(ABI协议)打包成32字节并一一拼接到一起。一个例外是:如果第一个参数恰好4个字节,在这种情况下,会被认为根据ABI协议定义的函数器指定的函数签名而直接使用。如果仅想发送消息体,需要避免第一个参数是4个字节。如下面的例子:
address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;nameReg.call("register", "MyName");nameReg.call(bytes4(keccak256("fun(uint256)")), a);

call()

是一个底层的接口,用来向一个合约发送消息,也就是说如果你想实现自己的消息传递,可以使用这个函数。函数支持传入任意类型的任意参数,并将参数打包成32字节,相互拼接后向合约发送这段数据。 call函数返回一个bool值,以表明执行成功与否。正常结束返回true,异常终止返回false。但无法获取到结果数据。还可以提供.gas()修饰器进行调用:
namReg.call.gas(1000000)("register", "MyName");

类似还可以提供附带以太币:
nameReg.call.value(1 ether)("register", "MyName");

修饰器可以混合使用,修饰器调用顺序无所谓。
nameReg.call.gas(1000000).value(1 ether)("register", "MyName");

delegatecall()

call与delegatecall的功能类似,区别仅在于后者仅使用给定地址的代码,仅仅是代码会执行,其它信息则使用当前合约(如存储,余额等等)。

函数的设计目的是为了使用存储在另一个合约的库代码。

所以开发者在提供这样的库时,就要如何安排存储来达到这样的目的。

delegatecall()方法的目的是用来执行另一个合约中的库代码。所以开发者需要保证两个合约中的存储变量能兼容,来保证delegatecall()能顺利执行。

callcode()

未提供对msg.sender,msg.value的访问权限。

call和callcode以及delegateCall的区别

三者的区别主要体现在三个方面,作用域(上下文)、msg.sender、以及this。

以下是比较示例:
contract D { uint public n; address public sender; function callSetN(address _e, uint _n) { _e.call(bytes4(sha3("setN(uint256)")), _n); // 执行结果:改变了E中的变量值, 而当前的同名变量并没改变。 } function callcodeSetN(address _e, uint _n) { _e.callcode(bytes4(sha3("setN(uint256)")), _n); // 执行结果:当前状态变量被改变,而E的并没改变。 } function delegatecallSetN(address _e, uint _n) { _e.delegatecall(bytes4(sha3("setN(uint256)")), _n); //执行结果同callcode }}contract E { uint public n; address public sender; function setN(uint _n) { n = _n; sender = msg.sender; // 如果D用call的方式调用,则msg.sender是D的合约地址 //如果D用callcode的方式调用,则msg.sender不会被获取 //如果D用delegateCall的方式调用,msg.sender也不能被获取 // 如果是C中的函数foo()间接调用了. msg.sender则是C // 如果D用callcode或者delegateCall调用,则this指向D }}contract C { function foo(D _d, E _e, uint _n) { _d.delegatecallSetN(_e, _n); }}

上面的这三个方法call(),delegatecall(),callcode()都是底层的消息传递调用,最好仅在万不得已才进行使用,因为他们破坏了Solidity的类型安全。 .gas() 在call(), callcode() 和 delegatecall() 函数下都可以使用, delegatecall()不支持.value()。
pragma solidity ^0.4.24;contract Person{ uint age = 10; function increaseAge(string name, uint num) returns (uint){ return ++age; } function getAge() returns (uint){ return age; }}contract CallTest{ function callByFun(address addr)returns (bool){ bytes4 methodId = bytes4(keccak256("increaseAge(string,uint256)")); return addr.call(methodId,"jack", 1); }}

注意
合约中使用的this表示当前合约地址所有的合约对象都可以被转成地址类型,查询当前合约的余额
address(this).balancethis.balance

-END-


「链块技术38期」以太坊智能合约-Solidity变量类型:值类型 上


附上链块学院网课学习平台链接:http://wk.liankuai.tech/

助教卫星:lkxy007


添加新手交流群:币种分析、每日早晚盘分析

添加助理微信,一对一亲自指导:YoYo8abc

查看更多:

为您推荐