以太坊智能合约编写Solidty基础(一)(懵逼的几个关键字)

solidity 函数的访问权限

solidity 函数分为四种访问权限:

 private : 私有函数。内部正常访问,外部无法访问,子类无法继承。

 internal : 内部函数。内部正常访问,外部无法访问,子类可继承。

 public : 公共函数。内部正常访问,外部正常访问,子类可继承。

 external : 外部函数。内部不能访问,外部正常访问,子类可继承。

solidity 函数中 pure 、 view 、 constant 的区别

只有当函数有返回值的情况下,才需要使用 pure 、 view 、 constant

pure : 当函数返回值为自变量而非变量时,使用 pure

view : 当函数返回值为全局变量或属性时,使用 view

constant : 可以理解为 view 的旧版本,与 view 是等价的

如果一个函数有返回值,函数中正常来讲需要有 pure 、 view 或 constant 关键字,如果没有,在调用函数的过程中,需要主动去调用底层的call方法。
注: 如果一个函数中带了关键字 view 或 constant ,就不能修改状态变量的值。但凡是是带了这两个关键字,区块链就默认只是向区块链读取数据,读取数据不需要花gas,但是不花gas就不可能修改状态变量的值。写入数据或者是修改状态变量的值都需要花费gas。

状态变量、函数的权限

public
 public类型的状态变量和函数的权限最大,可供外部、子合约、合约内部访问

 internal
 internal类型的状态变量可供外部和子合约调用。
 internal类型的函数和private类型的函数一样,智能合约自己内部调用,它和其他语言中的protected不完全一样

 private
 我们在person合约中尝试调用_name状态变量,你会发现,编译没法通过。

 重写
 子合约可以将父合约的public类型的函数,只能继承public类型的函数,只能继承public类型的函数,只能继承public类型的函数,我们可以直接调用继承过来的函数,当然,我们还可以对继承过来的函数进行重写。

构造器(智能合约)

每个合约都允许存在构造器,构造器是与合约同名的一个特殊函数,有且只能有一个,不允许重载。构造器将在合约创建时,执行一次,用于初始化一些配置。
pragma solidity ^0.4.0;

contract ContractConstructor{
  uint public counter;

  function ContractConstructor(){
    counter++;
  }
}
上述合约在创建成功后,counter的值将为1。说明合约在创建时,被调用了一次。构造器内,由于合约尚未初始化完成,故不能使用this来以external的方式来调用当前合约中的函数,

payable关键字

构造器还允许接收ether,只需要在构造器函数上增加payable关键字,下面是一个简单的例子:
pragma solidity ^0.4.0;

contract ConstructorEther{
    function ConstructorEther() payable {}
    function getBalance() constant returns (uint){
        return this.balance;
    }
}
在上面的例子中,ConstructorEther可以在创建时接收指定数量的ether。

payable标识

细心的读者可能发现在deposit函数上有一个payable关键字,如果一个函数需要进行货币操作,必须要带上payable关键字,这样才能正常接收msg.value。

indexed关键字

事件中,我们对_sender标记为了indexed。原因是因为为了提高查找事件的性能
contract CryptoExchange {
    event Deposit(uint256 indexed _market, address indexed _sender, uint256 _amount, uint256 _time);
    function deposit(uint256 _amount, uint256 _market) returns (int256) {
        // perform deposit, update user’s balance, etc
      Deposit(_market, msg.sender, _amount, now);
}

函数修改器(Function Modifiers)

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

下面我们来看一段示例代码:

pragma solidity ^0.4.0;

contract owned {
    function owned() { owner = msg.sender; }
    address owner;

    // This contract only defines a modifier but does not use
    // it - it will be used in derived contracts.
    // The function body is inserted where the special symbol
    // "_;" in the definition of a modifier appears.
    // This means that if the owner calls this function, the
    // function is executed and otherwise, an exception is
    // thrown.
    modifier onlyOwner {
        if (msg.sender != owner)
            throw;
        _;
    }
}


contract mortal is owned {
    // This contract inherits the "onlyOwner"-modifier from
    // "owned" and applies it to the "close"-function, which
    // causes that calls to "close" only have an effect if
    // they are made by the stored owner.
    function close() onlyOwner {
        selfdestruct(owner);
    }
}


contract priced {
    // Modifiers can receive arguments:
    modifier costs(uint price) {
        if (msg.value >= price) {
            _;
        }
    }
}


contract Register is priced, owned {
    mapping (address => bool) registeredAddresses;
    uint price;

    function Register(uint initialPrice) { price = initialPrice; }

    // It is important to also provide the
    // "payable" keyword here, otherwise the function will
    // automatically reject all Ether sent to it.
    function register() payable costs(price) {
        registeredAddresses[msg.sender] = true;
    }

    function changePrice(uint _price) onlyOwner {
        price = _price;
    }
}
修改器可以被继承,使用将modifier置于参数后,返回值前即可。
特殊_表示使用修改符的函数体的替换位置。
从合约Register可以看出全约可以多继承,通过,号分隔两个被继承的对象。
修改器也是可以接收参数的,如priced的costs。

使用修改器实现的一个防重复进入的例子。

pragma solidity ^0.4.0;
contract Mutex {
    bool locked;
    modifier noReentrancy() {
        if (locked) throw;
        locked = true;
        _;
        locked = false;
    }

    /// This function is protected by a mutex, which means that
    /// reentrant calls from within msg.sender.call cannot call f again.
    /// The `return 7` statement assigns 7 to the return value but still
    /// executes the statement `locked = false` in the modifier.
    function f() noReentrancy returns (uint) {
        if (!msg.sender.call()) throw;
        return 7;
    }
}

fromBlock参数

默认情况下,当事件发生时,我们才开始监听。但当UI首次加载时,由于没有事件发生,没有对应的存款记录需要展示。所以为了展示用户的历史存款记录,我们需要从0号区块开始搜索用户的事件,这可以通过增加一个fromBlock参数来实现。
var depositEventAll = cryptoExContract.Deposit({_sender: userAddress}, {fromBlock: 0, toBlock: 'latest'});
depositEventAll.watch(function(err, result) {
  if (err) {
    console.log(err)
    return;
  }
  // append details of result.args to UI
})
 UI加载完成后,切记调用depositEventAll.stopWatching()来去掉监听。

   最多可以有三个参数是索引的。举例来说,基本的代币行为有event Transfer(address indexed _from, address indexed _to, uint256 _value)。所以为了有效的监听转帐行为,你可以:
   监听发送帐号tokenContract.Transfer({_from: senderAddress})。
   监听收款帐号tokenContract.Transfer({_to: receiverAddress})。
   同时监听发送,收款帐号tokenContract.Transfer({_from: senderAddress, _to: receiverAddress})。

常用属性

   block.coinbase (address): 当前块的矿工的地址
   block.difficulty (uint):当前块的难度系数
   block.gaslimit (uint):当前块汽油限量
   block.number (uint):当前块编号
   block.blockhash (function(uint) returns (bytes32)):指定块的哈希值——最新的256个块的哈希值
   block.timestamp (uint):当前块的时间戳
   msg.data (bytes):完整的calldata
   msg.gas (uint):剩余的汽油
   msg.sender (address):消息的发送方(当前调用)
   msg.sig (bytes4):calldata的前四个字节(即函数标识符)
   msg.value (uint):所发送的消息中wei的数量
   now (uint):当前块时间戳(block.timestamp的别名)
   tx.gasprice (uint):交易的汽油价格
   tx.origin (address):交易发送方(完整的调用链)

你可能感兴趣的:(区块链,以太坊,Solidity,智能合约,关键字)