美文网首页Dapp开发
Solidity语法(三)其他类型

Solidity语法(三)其他类型

作者: yuyangray | 来源:发表于2018-02-27 17:24 被阅读476次

    Mapping

    mapping,简单地说mapping就是一种hashtable, 由一个key对应一个value是由键和值组成的mapping(_KeyType => _ValueType)哈希表,初始化每个存在的key,对应的value的值会初始化为所有的字节都为0。_KeyType和_ValueType可以是任意类型。mapping只允许静态变量或是内部方法中的存储空间引用类型。一般键为地址, 值为余额 mapping(address => uint)。键的类型允许除映射外的所有类型,如数组,合约,枚举,结构体。值的类型无限制。

    示例:

    pragma solidity 0.4.20;
    
    contract testMapping {
    
        mapping (bytes32 => uint) balances;
        
        /*
         * 初始化
         * 将key为Ray的value设置为100
         */
        function testMapping() {
            balances["Ray"] = 100;
        }
        
        /*
         * 获取map的指定key的值
         * 查询指定key的value,如果key不存在,会返回0
         */
        function getValueByKey(bytes32 key) returns(uint){
          return balances[key];
        }
    
        /*
         * 增加map的指定key的值
         */
        function add(bytes32 key, uint amount) {
            balances[key] += amount;
        }
    
        /*
         * 更新map的指定key的值
         */
        function update(bytes32 key, uint amount) {
            balances[key] = amount;
        }
    
        /*
         * 清空map的指定key的值
         */
        function del(bytes32 key) {
            balances[key] = 0;
        }
    }
    

    在Browser-solidity中调试:

    mapping

    用Mapping来实现一个简单的转账合约

    pragma solidity 0.4.20;
    contract TransContract {
    
    /**
     * 这里我们定义了一个address 作为key, uint做为value的balances; 
     * 我们还定义了一个address的变量minter;
     */
    
    address public minter;
    
    mapping (address => uint) public balances;
    
    /**
     * 定义一个事件 Sent() 
     */
    event Sent(address from, address to, uint amount);
    
    /**
     * 添加一个构造函数
     * 这里的代码minter = msg.sender; 代表创建这个合约的账户地址,被赋值给变量minter 
     */
    function TransContract() {
       minter = msg.sender;
    }
    
    /**
     * 这里的核心代码在于,如果调用这个方法的账户,不是minter, 也就是创建合约的账户的话,这个mint()将无法被执行。 只有是创建合约的账户,也就是minter 才可以执行它
     */
    function mint(address receiver, uint amount) {
       if (msg.sender != minter) throw;
       balances[receiver] += amount;
    }
    
    /**
     * 添加一个function send() 也就是从A转移X代币到B账户
     */
    function send(address receiver, uint amount) {
       if (balances[msg.sender] < amount) return;
       balances[msg.sender] -= amount;
       balances[receiver] += amount;
       Sent(msg.sender, receiver, amount);
     }
    }
    

    在Browser-solidity中调试:

    TransContract

    左值的相关运算符

    左值,是指位于表达式左边的变量,可以是与操作符直接结合的形成的,如自增,自减;也可以是赋值,位运算。

    可以支持操作符有:-=,+=,*=,%=,|=,&=,^=,++,--

    特殊的运算符delete

    delete运算符,用于将某个变量重置为初始值。对于整数,运算符的效果等同于a = 0。而对于定长数组,则是把数组中的每个元素置为初始值,变长数组则是将长度置为0。对于结构体,也是类似,是将所有的成员均重置为初始值。

    delete对于映射类型几乎无影响,因为键可能是任意的,且往往不可知。所以如果你删除一个结构体,它会递归删除所有非mapping的成员。当然,你是可以单独删除映射里的某个键,以及这个键映射的某个值。

    需要强调的是delete a的行为更像赋值,为a赋予一个新对象。我们来看看下文的示例:

    pragma solidity ^0.4.0;
    
    contract DeleteExample {
        uint data;
        uint[] dataArray;
    
        function f() {
            //值传递
            uint x = data;
            //删除x不会影响data
            delete x;
    
            //删除data,同样也不会影响x,因为是值传递,它存的是一份原值的拷贝。
            delete data; 
    
            //引用赋值
            uint[] y = dataArray;
    
            //删除dataArray会影响y,y也将被赋值为初值。
            delete dataArray;
    
            //下面的操作为报错,因为删除是一个赋值操作,不能向引用类型的storage直接赋值从而报错
            //delete y;
        }
    }
    

    通过上面的代码,我们可以看出,对于值类型,是值传递,删除x不会影响到data,同样的删除data也不会影响到x。因为他们都存了一份原值的拷贝。

    而对于复杂类型略有不同,复杂类型在赋值时使用的是引用传递。删除会影响所有相关变量。比如上述代码中,删除dataArray同样会影响到y

    由于delete的行为更像是赋值操作,所以不能在上述代码中执行delete y,因为不能对一个storage的引用赋值

    基本类型间的转换

    语言中经常会出现类型转换。如将一个数字字符串转为整型,或浮点数。这种转换常常分为,隐式转换和显式转换。

    隐式转换

    如果运算符支持两边不同的类型,编译器会尝试隐式转换类型,同理,赋值时也是类似。通常,隐式转换需要能保证不会丢失数据,且语义可通。如uint8可以转化为uint16,uint256。但int8不能转为uint256,因为uint256不能表示-1。

    此外,任何无符号整数,可以转换为相同或更大大小的字节值。比如,任何可以转换为uint160的,也可以转换为address。

    显式转换

    如果编译器不允许隐式的自动转换,但你知道转换没有问题时,可以进行强转。需要注意的是,不正确的转换会带来错误,所以你要进行谨慎的测试。

    pragma solidity ^0.4.0;
    
    contract DeleteExample{
        uint a;
        
        function f() returns (uint){
          int8 y = -3;
          uint x = uint(y);
          return x;
        }
    }
    

    如果转换为一个更小的类型,高位将被截断。

    uint32 a = 0x12345678;
    uint16 b = uint16(a); // b will be 0x5678 now
    

    类型推断(Type Deduction)

    为了方便,并不总是需要明确指定一个变量的类型,编译器会通过第一个向这个对象赋予的值的类型来进行推断。

    uint24 x = 0x123;
    var y = x;
    

    函数的参数,包括返回参数,不可以使用var这种不指定类型的方式。

    需要特别注意的是,由于类型推断是根据第一个变量进行的赋值。所以代码for (var i = 0; i < 2000; i++) {}将是一个无限循环,因为一个uint8的i的将小于2000。

    pragma solidity ^0.4.4;
    
    contract Test{
        function a() returns (uint){
          uint count = 0;
            for (var i = 0; i < 2000; i++) {
                count++;
                if(count >= 2100){
                    break;
                }
            }
            return count;
        }
    }
    

    相关文章

      网友评论

        本文标题:Solidity语法(三)其他类型

        本文链接:https://www.haomeiwen.com/subject/zzlmxftx.html