Dynamically-sized byte array
string是一個動態(tài)尺寸的UTF-8編碼字符串,它其實是一個特殊的可變字節(jié)數(shù)組,string是引用類型,而非值類型。bytes動態(tài)字節(jié)數(shù)組,引用類型。
根據(jù)經驗,在我們不確定字節(jié)數(shù)據(jù)大小的情況下,我們可以使用string或者bytes,而如果我們清楚的知道或者能夠將字節(jié)書控制在bytes1 ~ bytes32,那么我們就使用bytes1 ~ bytes32,這樣的話能夠降低存儲成本。
常規(guī)字符串 sting 轉換為 bytes
string字符串中沒有提供length方法獲取字符串長度,也沒有提供方法修改某個索引的字節(jié)碼,不過我們可以將string轉換為bytes,再調用length方法獲取字節(jié)長度,當然可以修改某個索引的字節(jié)碼。
pragma solidity ^0.4.4;
contract C {
bytes9 public g = 0x6c697975656368756e;
string public name = "liyuechun";
function gByteLength() constant returns (uint) {
return g.length;
}
function nameBytes() constant returns (bytes) {
return bytes(name);
}
function nameLength() constant returns (uint) {
return bytes(name).length;
}
function setNameFirstByteForL(bytes1 z) {
// 0x4c => "L"
bytes(name)[0] = z;
}
}

function nameBytes() constant returns (bytes) {
return bytes(name);
}
nameBytes這個函數(shù)的功能是將字符串name轉換為bytes,并且返回的結果為0x6c697975656368756e。0x6c697975656368756e一共為9字節(jié),也就是一個英文字母對應一個字節(jié)。
function nameLength() constant returns (uint) {
return bytes(name).length;
}
我們之前講過,string字符串它并不提供length方法幫助我們返回字符串的長度,所以在nameLength方法中,我們將name轉換為bytes,然后再調用length方法來返回字節(jié)數(shù),因為一個字節(jié)對應一個英文字母,所以返回的字節(jié)數(shù)量剛好等于字符串的長度。
function setNameFirstByteForL(bytes1 z) {
// 0x4c => "L"
bytes(name)[0] = z;
}
如果我們想將name字符串中的某個字母進行修改,那么我們直接通過x[k] = z的形式進行修改即可。x是bytes類型的字節(jié)數(shù)組,k是索引,z是byte1類型的變量值。
setNameFirstByteForL方法中,我就將liyuechun中的首字母修改成L,我傳入的z的值為0x4c,即大寫的L。
漢字字符串或特殊字符的字符串轉換為bytes
特殊字符
pragma solidity ^0.4.4;
contract C {
string public name = "a!+&520";
function nameBytes() constant returns (bytes) {
return bytes(name);
}
function nameLength() constant returns (uint) {
return bytes(name).length;
}
}

在這個案例中,我們聲明了一個name字符串,值為a!+&520,根據(jù)nameBytes和nameLength返回的結果中,我們不難看出,不管是字母、數(shù)字還是特殊符號,每個字母對應一個byte(字節(jié))。
中文字符串
pragma solidity ^0.4.4;
contract C {
string public name = "黎躍春";
function nameBytes() constant returns (bytes) {
return bytes(name);
}
function nameLength() constant returns (uint) {
return bytes(name).length;
}
}

在上面的代碼中,我們不難看出,黎躍春轉換為bytes以后的內容為0xe9bb8ee8b783e698a5,一共9個字節(jié)。也就是一個漢字需要通過3個字節(jié)來進行存儲。那么問題來了,以后我們取字符串時,字符串中最好不要帶漢字,否則計算字符串長度時還得特殊處理。
創(chuàng)建bytes字節(jié)數(shù)組
pragma solidity ^0.4.4;
contract C {
bytes public name = new bytes(1);
function setNameLength(uint length) {
name.length = length;
}
function nameLength() constant returns (uint) {
return name.length;
}
}

bytes可變數(shù)組length和push兩個函數(shù)的使用案例
pragma solidity ^0.4.4;
contract C {
// 0x6c697975656368756e
// 初始化一個兩個字節(jié)空間的字節(jié)數(shù)組
bytes public name = new bytes(2);
// 設置字節(jié)數(shù)組的長度
function setNameLength(uint len) {
name.length = len;
}
// 返回字節(jié)數(shù)組的長度
function nameLength() constant returns (uint) {
return name.length;
}
// 往字節(jié)數(shù)組中添加字節(jié)
function pushAByte(byte b) {
name.push(b);
}
}

說明:當字節(jié)數(shù)組的長度只有2時,如果你通過push往里面添加了一個字節(jié),那么它的長度將變?yōu)?,當字節(jié)數(shù)組里面有3個字節(jié),但是你通過length方法將其長度修改為2時,字節(jié)數(shù)組中最后一個字節(jié)將被從字節(jié)數(shù)組中移除。
總結
對比分析:
- 不可變字節(jié)數(shù)組
我們之前的文章中提到過如果我們清楚我們存儲的字節(jié)大小,那么我們可以通過bytes1,bytes2,bytes3,bytes4,……,bytes32來聲明字節(jié)數(shù)組變量,不過通過bytesI來聲明的字節(jié)數(shù)組為不可變字節(jié)數(shù)組,字節(jié)不可修改,字節(jié)數(shù)組長度不可修改。
- 可變字節(jié)數(shù)組
我們可以通過bytes name = new bytes(length) - length為字節(jié)數(shù)組長度,來聲明可變大小和可修改字節(jié)內容的可變字節(jié)數(shù)組。
原文:Solidity Types - 動態(tài)大小字節(jié)數(shù)組(Dynamically-sized byte array)
作者:黎躍春