Solidity语法(三)其他类型

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;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容