ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

solidity语法(二)

2021-05-27 11:04:38  阅读:245  来源: 互联网

标签:function 调用 函数 solidity 语法 uint msg 合约


继续学习solidity语法。

2.1 函数类型

 

以下是在Solidity中声明函数的方式。

function sampleFunc(string name, uint amount) {}

上面声明的是一个空体函数,它有两个参数:一个字符串和一个 uint。

可以这样调用此函数:

sampleFunc("Shashank", 10000);

谈到函数,Solidity还提供函数修饰符。

 

2.2 函数四种访问权限

 

函数声明有public、private、internal和external四种访问权限

  • 1.函数默认声明为public,即可以以internal方式调用,也可以通过external方式调用。可以理解为能够被内部合约访问和外部合约访问。

  • 2.Internal声明的只允许通过internal方式调用,不能被外部合约。而external能够被外部合约访问。

  • 3.private和internal类似,都不能被外部合约访问,唯一的不同是private函数不能被子类调用,而internal可以。

contract FunctionTest{        function publicFunc() {}    function callFunc(){        //以`internal`的方式调用函数        publicFunc();                //以`external`的方式调用函数        this.publicFunc();    }        function internalFunc() internal{}        function externalFunc() external{}        }contract FunctionTest1 {    function externalCall(FuntionTest ft){        //调用另一个合约的外部函数        ft.publicFunc();        ft.externalFunc();       //ft.internalFunc();调用失败,无法调用internal函数    }}


 

2.3 pure、view、constant函数返回值定义类型

 

当函数有返回值时,可以添加这三种定义,用这三种方式定义的函数都只执行读操作,不会进行编译执行。即用了这三种方式定义的函数,不会执行函数里的逻辑,只会执行一个返回的读操作。所以执行这些函数不需要消耗gas费用。

  • pure区别是用于返回非变量,如returns 10;

  • 而view和constant用于返回全局变量,两者的区别为新旧版本

  • 但是此功能4.x版本可用,5.x版本废弃

  • 声明才能返回

contract HelloWorld4{        uint public a = 1;      //由于被constant声明的函数执行读操作,所以a无法被修改    //执行为f(),a依然为1    function f() constant{       a = 3;    }}

2.4 函数修饰符

 

函数修饰符看起来跟函数没什么不同,不过关键字modifier 告诉编译器,这是个modifier(修饰符),而不是个function(函数)。它不能像函数那样被直接调用,只能被添加到函数定义的末尾,用以改变函数的行为。

示例:如果要仅通过函数的所有者或创建者调用kill contract函数。

/** * @dev 调用者不是‘主人’,就会抛出异常 */modifier onlyOwner() {  require(msg.sender == owner);  _;}onlyOwner 函数修饰符是这么用的:onlyOwner,它会限制陌生人的访问,将访问某些函数的权限锁定在 owner 上contract MyContract is Ownable {  event LaughManiacally(string laughter);  //注意!`onlyOwner`上场 :  function likeABoss() external onlyOwner {    LaughManiacally("Muahahahaha");  }}

修改器(Modifiers)可以用来轻易的改变一个函数的行为。比如用于在函数执行前检查某种前置条件。修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)。

 

 

2.5 继承

 

Solidity通过复制包含多态的代码来支持多重继承。

contract Owned {    address Owner ;    function owned() {       owner = msg.sender;    }}contract Mortal is Owned {  // 'is' keyword is used for inheritance     function kill(){         self-destruct(owner);        }}contract User is Owned, Mortal{ //Multiple inheritance(多重继承)     string public UserName;     function User(string _name){         UserName = _name;     }}

 

2.6 事件

 

在Solidity 代码中,使用event 关键字来定义一个事件,如:

event EventName(address bidder, uint amount);

这个用法和定义函数式一样的,并且事件在合约中同样可以被继承。触发一个事件使用emit(说明,之前的版本里并不需要使用emit),如:

emit EventName(msg.sender, msg.value);

触发事件可以在任何函数中调用,如:

function testEvent() public {    // 触发一个事件     emit EventName(msg.sender, msg.value); }

 

2.7 异常处理

 

Solidity使用状态恢复来处理异常,就是说当抛出异常时将恢复到调用(包括自调用)前的状态。

抛出异常的方式有assert,require,revert,throw。

 

 assert函数,用于条件检查,只能测试内部错误和检查常量。

//检查内部计算是否会整型溢出function add(uint256 a, uint256 b) internal constant returns (uint256) {    uint256 c = a + b;    assert(c >= a);    return c;  }

 require函数,也是用于条件检查,用于测试调用的输入或者合约状态变量。

function sendHalf(address addr) payable returns (uint balance) {        require(msg.value % 2 == 0); // 只允许偶数        .....    }

revert 函数用于标记错误并恢复当前调用。

function buy(uint amount) payable {        if (amount > msg.value / 2 ether)            revert("Not enough Ether provided.");    }

throw 和revert一样,但是throw在0.4.13被弃用,将来会被淘汰。

 

2.8 状态变量storage和局部变量memory

 

两者区别很容易理解,memory可以理解为临时变量,不会记录在链上,而storage是永久存储的。

变量定义时默认为storage,而作为函数参数时,默认为memory

contract HelloWorld{        //等价于 string storage public a;    string public a;    //参数等价于string memory _a    function changeNum(string _a){    }        }

当函数参数为memory类型时,相当于值传递,storage才是指针传递

contract HelloWorld2{        string public a;        function HelloWorld2(){        a = "abc";    }            function f(){        changeNum(a);    }        function changeNum(string _a){        bytes(_a)[0] = "d";      //由于_a默认为memory,所以_a只是值传递,所以此时修改a的值是不成功的,输出还是abc      //需要把函数参数修改为string storage _a,才能输出dbc    }}

将变量赋值给一个新变量时,新变量的类型由赋值给它的类型决定。

function changeNum(string _a){        //_a默认为memory类型,所以b也为memory        string b = _a;        bytes(_a)[0] = "d";    }

 

2.9 接口

 

如果我们的合约需要和区块链上的其他的合约会话,则需先定义一个 interface (接口)。

假设在区块链上有这么一个合约:

contract LuckyNumber {  mapping(address => uint) numbers;  function setNum(uint _num) public {    numbers[msg.sender] = _num;  }  function getNum(address _myAddress) public view returns (uint) {    return numbers[_myAddress];  }}

现在假设我们有一个外部合约,使用 getNum 函数可读取其中的数据。

首先,我们定义 LuckyNumber 合约的 interface :

contract NumberInterface {  function getNum(address _myAddress) public view returns (uint);}

在我们的 app 代码中使用这个接口,合约就知道其他合约的函数是怎样的,应该如何调用,以及可期待什么类型的返回值。

上面的接口,我们可以在合约中这样使用:

contract MyContract {  address NumberInterfaceAddress = 0xab38...;  // ^ 这是FavoriteNumber合约在以太坊上的地址  NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);  // 现在变量 `numberContract` 指向另一个合约对象  function someFunction() public {    // 现在我们可以调用在那个合约中声明的 `getNum`函数:    uint num = numberContract.getNum(msg.sender);    // ...在这儿使用 `num`变量做些什么  }}

通过这种方式,只要将您合约的可见性设置为public(公共)或external(外部),它们就可以与以太坊区块链上的任何其他合约进行交互。

处理多返回值

function multipleReturns() internal returns(uint a, uint b, uint c) {  return (1, 2, 3);}function processMultipleReturns() external {  uint a;  uint b;  uint c;  // 这样来做批量赋值:  (a, b, c) = multipleReturns();}// 或者如果我们只想返回其中一个变量:function getLastReturnValue() external {  uint c;  // 可以对其他字段留空:  (,,c) = multipleReturns();}


3.0 payable 修饰符

 

payable 方法是让 Solidity 和以太坊变得如此酷的一部分 —— 它们是一种可以接收以太的特殊函数。

在以太坊中, 因为钱 (以太), 数据 (事务负载), 以及合约代码本身都存在于以太坊。你可以在同时调用函数 并付钱给另外一个合约。

contract OnlineStore {  function buySomething() external payable {    // 检查以确定0.001以太发送出去来运行函数:    require(msg.value == 0.001 ether);    // 如果为真,一些用来向函数调用者发送数字内容的逻辑    transferThing(msg.sender);  }}

在这里,msg.value 是一种可以查看向合约发送了多少以太的方法,另外 ether 是一个內建单元。

这里发生的事是,一些人会从 web3.js 调用这个函数 (从DApp的前端), 像这样 :

 

// 假设 OnlineStore 在以太坊上指向你的合约:OnlineStore.buySomething().send(from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001))

注意这个 value 字段, JavaScript

调用来指定发送多少(0.001)以太。如果把事务想象成一个信封,你发送到函数的参数就是信的内容。添加一个 value 很像在信封里面放钱

—— 信件内容和钱同时发送给了接收者。


 

3.1 基本类型之间的转换

 

隐式转换

 

  如果一个运算符用在两个不同类型的变量之间,编译器将会隐式地将其中一个类型转换成另一个类型。一般来说,只要值类型之间的转换在语义上能行,而且转换过程没有信息丢失,基本上都是可行的。

  如uint8转换成uint16,uint128转换成uint256,但是uint8不能转换成uint256(因为uint256不能涵盖某些值如-1)。通常无符号整型内转换成与它大小相等或者更大的字节类型,反之不能。任何可以转换成uint160的类型都能转换成地址类型。

 

显式转换

 

  某些情况编译器不支持隐式转换,但是用户清楚他在做什么,这时候可以使用显式转换。一定要先进行测试,保证结果可控。

示例:

int8 y = -3;uint x = uint(y);

  x值将为 0xfff...fd(63个f),这是-3的256位补码形式

如果一个显式转换成更小的类型,相应的高位会被抛弃:

uint32 a = 0x12345678;uint16 b = uint16(a); // b的值为 0x5678

 

3.2 内置单位

 

1、货币单位

weifinneyszaboether若不加后缀,则默认都为wei

2、时间单位

1==1 seconds1 minutes == 60 seconds ……特别注意,使用这些单位时要特别小心,因为一年并不总有365天;同时因为有闰秒的存在,一天也并不总是24小时。为了保证日历库的精确性,最好由外部供应商定期更新。

3、区块和交易属性 

block.blockhash(uint blockNumber) returns(bytes32):获取特定区块的散列值,只对不包括当前区块的256个最近的区块有效。block.coinbase:类型为address,表示当前区块“矿工”的帐号地址block.difficulty:类型为uint,表示当前区块的挖矿难度block.gaslimit:类型为uint,表示当前区块的Gas限制block.number:类型为uint,表示当前区块编号block.timestamp:类型为uint,以UNIX时间戳的形式表示当前区块的产生时间msg.data:类型为bytes,表示完整的调用数据msg.gas:类型为uint,表示剩余的Gasmsg.sender:类型为address,表示当前消息的发送者地址msg.sig:类型为bytes4,调用数据的前4字节,函数标识符msg.value:类型为uint,表示该消息转账的以太币数额,单位为weinow:类型为uint,表示当前时间,是block.timestamp的别名。tx.gasprice:类型为uint,表示当前交易Gas价格tx.origin:类型为address,表示完整调用链的发起者。

5、数学和加密函数

 

addmod(uint x,uint y,uint k) returns(uint):计算(x+y)%k,加法支持任意精度,但不超过2的256次方mulmod(uint x,uint y,uint k) returns(uint):计算(x*y)%k,乘法支持任意精度,但不超过2的256次方keccak256(...) returns(bytes32):计算Ethereum-SHA-3散列值sha3(...) returns(bytes32):上面的别名,跟上面功能一样sha256(...) returns(bytes20):计算RIPEMD-160散列值ecrecover(bytes32 hash,uint8 v,bytes32 r,bytes32 s) returns (address):根据公钥,使用ECDSA算法对地址进行解密,返回解密后的地址,如果发生错误,则返回0

6、与合约相关的变量和函数

this:指代当前的合约,可以转换为地址类型selfdestruct(address recipient):销毁当前合约,并且将全部的以太币余额转账到该地址。suicide(address recipient):同上 

 

标签:function,调用,函数,solidity,语法,uint,msg,合约
来源: https://blog.csdn.net/S123456215/article/details/117323707

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有