『0015』 - Solidity Types - 动态字节数组(Dynamically-sized byte array)、固定大小字节数组(Fixed-size byte arrays)、string之间的转换关系

简介:

孔壹学院:国内区块链职业教育领先品牌

作者:黎跃春,区块链、高可用架构工程师
微信:liyc1215 QQ群:348924182 博客:http://liyuechun.org

固定大小字节数组(Fixed-size byte arrays)之间的转换

固定大小字节我们可以通过bytes0 ~ bytes32来进行声明,固定大小字节数组的长度不可变,内容不可修改。接下来我们通过下面的代码看看固定大小字节之间的转换关系。

pragma solidity ^0.4.4;

contract C {
    
    
   bytes9 name9 = 0x6c697975656368756e;
    
   
   function bytes9ToBytes1() constant returns (bytes1) {
       
       return bytes1(name9);
   }
   
   function bytes9ToBytes2() constant returns (bytes2) {
       
       return bytes2(name9);
   }
   
   function bytes9ToBytes32() constant returns (bytes32) {
       
       return bytes32(name9);
   }
    
}

固定大小字节之间的转换

结论:bytes9bytes1或者bytes2时,会进行低位截断,0x6c697975656368756e转换为bytes1,结果为0x6c,转换为bytes2时结果为0x6c69。当0x6c697975656368756e转换为bytes32时会进行低位补齐,结果为0x6c697975656368756e0000000000000000000000000000000000000000000000

固定大小字节数组(Fixed-size byte arrays)转动态大小字节数组(Dynamically-sized byte array)

pragma solidity ^0.4.4;

contract C {
    
    
   bytes9 name9 = 0x6c697975656368756e;
    
   function fixedSizeByteArraysToDynamicallySizedByteArray() constant returns (bytes) {
       
       return bytes(name9);
   }
    
}

对于刚接触的童鞋,很多人都会用上面的方法进行转换,以为理所当然,殊不知编译运行时,代码报错,原因如下:

固定大小字节数组转动态大小字节数组

备注:简言之,固定大小字节数组动态大小字节数组之间不能简单直接转换。

下面是固定大小字节数组转动态大小字节数组正确的姿势。

pragma solidity ^0.4.4;

contract C {
    
   bytes9 name9 = 0x6c697975656368756e;
    
   function fixedSizeByteArraysToDynamicallySizedByteArray() constant returns (bytes) {
       
       bytes memory names = new bytes(name9.length);
       
       for(uint i = 0; i < name9.length; i++) {
           
           names[i] = name9[i];
       }
       
       return names;
   }
    
}

在上面的代码中,我们根据固定字节大小数组的长度来创建一个memory类型的动态类型的字节数组,然后通过一个for循环将固定大小字节数组中的字节按照索引赋给动态大小字节数组即可。

固定大小字节数组(Fixed-size byte arrays)不能直接转换为string

pragma solidity ^0.4.4;

contract C {
    
    bytes9 names = 0x6c697975656368756e;
    
    function namesToString() constant returns (string) {
        
        return string(names);
    }
   
}

定大小字节数组(Fixed-size byte arrays)不能直接转换为string

动态大小字节数组(Dynamically-sized byte array)转string

重要:因为string是特殊的动态字节数组,所以string只能和动态大小字节数组(Dynamically-sized byte array)之间进行转换,不能和固定大小字节数组进行转行。

  • 如果是现成的动态大小字节数组(Dynamically-sized byte array),如下:
pragma solidity ^0.4.4;

contract C {
    
    bytes names = new bytes(2);
    
    function C() {
        
        names[0] = 0x6c;
        names[1] = 0x69;
    }
    
    
    function namesToString() constant returns (string) {
        
        return string(names);
    }
   
}

如果是现成的动态大小字节数组(Dynamically-sized byte array)

  • 如果是固定大小字节数组转string,那么就需要先将字节数组转动态字节数组,再转字符串
pragma solidity ^0.4.4;

contract C {

   function byte32ToString(bytes32 b) constant returns (string) {
       
       bytes memory names = new bytes(b.length);
       
       for(uint i = 0; i < b.length; i++) {
           
           names[i] = b[i];
       }
       
       return string(names);
   }
   
}

如果是固定大小字节数组转string,那么就需要先将字节数组转动态字节数组,再转字符串
可以通过0x6c697975656368756e作为参数进行测试,右边的返回结果看似liyuechun,它的实际内容为liyuechun\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000,所以在实际的操作中,我们应该将后面的一些列\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000去掉。

  • 正确的固定大小字节数组转string的代码
pragma solidity ^0.4.4;

contract C {
    
    function bytes32ToString(bytes32 x) constant returns (string) {
        bytes memory bytesString = new bytes(32);
        uint charCount = 0;
        for (uint j = 0; j < 32; j++) {
            byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
            if (char != 0) {
                bytesString[charCount] = char;
                charCount++;
            }
        }
        bytes memory bytesStringTrimmed = new bytes(charCount);
        for (j = 0; j < charCount; j++) {
            bytesStringTrimmed[j] = bytesString[j];
        }
        return string(bytesStringTrimmed);
    }

    function bytes32ArrayToString(bytes32[] data) constant returns (string) {
        bytes memory bytesString = new bytes(data.length * 32);
        uint urlLength;
        for (uint i = 0; i< data.length; i++) {
            for (uint j = 0; j < 32; j++) {
                byte char = byte(bytes32(uint(data[i]) * 2 ** (8 * j)));
                if (char != 0) {
                    bytesString[urlLength] = char;
                    urlLength += 1;
                }
            }
        }
        bytes memory bytesStringTrimmed = new bytes(urlLength);
        for (i = 0; i < urlLength; i++) {
            bytesStringTrimmed[i] = bytesString[i];
        }
        return string(bytesStringTrimmed);
    }    
}

byte char = byte(bytes32(uint(x) * 2 ** (8 * j)))在上面的代码中,估计大家最难看懂的就是这一句代码,我们通过下面的案例给大家解析:

pragma solidity ^0.4.4;

contract C {
    
    // 0x6c
    
    function uintValue() constant returns (uint) {
        
        return uint(0x6c);
    }
    
    function bytes32To0x6c() constant returns (bytes32) {
        
        return bytes32(0x6c);
    }
    
    function bytes32To0x6cLeft00() constant returns (bytes32) {
        
        return bytes32(uint(0x6c) * 2 ** (8 * 0));
    }
    
    function bytes32To0x6cLeft01() constant returns (bytes32) {
        
        return bytes32(uint(0x6c) * 2 ** (8 * 1));
    }
    
    function bytes32To0x6cLeft31() constant returns (bytes32) {
        
        return bytes32(uint(0x6c) * 2 ** (8 * 31));
    }
}

  • bytes32(uint(0x6c) * 2 ** (8 * 31));左移31位
  • bytes32(uint(0x6c) * 2 ** (8 * 1)); 左移1位

通过byte(bytes32(uint(x) * 2 ** (8 * j)))获取到的始终是第0个字节。

总结

string本身是一个特殊的动态字节数组,所以它只能和bytes之间进行转换,不能和固定大小字节数组进行直接转换,如果是固定字节大小数组,需要将其转换为动态字节大小数组才能进行转换。

技术交流

  • 区块链技术交流QQ群:348924182
  • 「区块链部落」官方公众号

相关文章
|
XML 数据格式
hutool将XML文档转换为String
hutool将XML文档转换为String
|
JavaScript 前端开发 开发者
|
存储 Go 索引
Golang 中的 String、rune 和 byte
Golang 中的 String、rune 和 byte
|
测试技术 Go API
golang []byte和string的高性能转换
golang []byte和string的高性能转换
273 1
|
存储 NoSQL Redis
Redis07命令-String类型字符串,不管是哪种格式,底层都是字节数组形式存储的,最大空间不超过512m,SET添加,MSET批量添加,INCRBY age 2可以,MSET,INCRSETEX
Redis07命令-String类型字符串,不管是哪种格式,底层都是字节数组形式存储的,最大空间不超过512m,SET添加,MSET批量添加,INCRBY age 2可以,MSET,INCRSETEX
数据存储之数组的特点,长度固定,适应变化需求,集合类特点是空间可变,ArrayList泛型,ArrayList<String> array = new ArrayList<String>()
数据存储之数组的特点,长度固定,适应变化需求,集合类特点是空间可变,ArrayList泛型,ArrayList<String> array = new ArrayList<String>()
new String()定义字符串为空,char[] chs = {‘a‘,‘b‘,‘c‘} String s2 = new String(chs) 输出abc,byte定99为a
new String()定义字符串为空,char[] chs = {‘a‘,‘b‘,‘c‘} String s2 = new String(chs) 输出abc,byte定99为a
byte[]转换成String
byte[]转换成String
594 0
|
存储 自然语言处理 Java
Java_9_为何要将_String_的底层实现由_char[]_改成了_byte[]_?
Java_9_为何要将_String_的底层实现由_char[]_改成了_byte[]_?
|
JavaScript
ES6对String字符串、Array数组、Number数字、Object对象 类型做了哪些升级优化
ES6对String字符串、Array数组、Number数字、Object对象 类型做了哪些升级优化
252 0

热门文章

最新文章

  • 1
    PHP 数组查找:为什么 `isset()` 比 `in_array()` 快得多?
    266
  • 2
    Java 中数组Array和列表List的转换
    968
  • 3
    JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
    696
  • 4
    通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式、聚合统计、处理树结构数据和性能优化,reduce()的使用详解(附实际应用代码)
    1521
  • 5
    通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
    640
  • 6
    通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
    449
  • 7
    多维数组操作,不要再用遍历循环foreach了!来试试数组展平的小妙招!array.flat()用法与array.flatMap() 用法及二者差异详解
    293
  • 8
    别再用双层遍历循环来做新旧数组对比,寻找新增元素了!使用array.includes和Set来提升代码可读性
    295
  • 9
    Array.forEach实战详解:简化循环与增强代码可读性;Array.forEach怎么用;面对大量数据时怎么提高Array.forEach的性能
    178
  • 10
    深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解
    727