Solidity是一種靜態(tài)類型語言,意思是每個變量(聲明和本地)在編譯時刻都要定義 (或者至少要知曉,參看 后面的類型導(dǎo)出 )。
Solidity提供幾個基本類型組合成復(fù)雜類型。
以下類型被叫做值類型,因為這些類型的變量總是要被賦值,作為函數(shù)參數(shù)或者在賦值中,總需要拷貝。
布爾:可能的常量值 是 真或假
操作符:
!(邏輯非)
&&(邏輯與,“and")
||?? (邏輯或,”or“)
==(相等)
!=(不等)
int? / uint?: 是有符號和無符號的整數(shù),關(guān)鍵字uint8 到 uint256 步長8 (從8到256位的無符號整數(shù) )
?uint 和 int 分別是 uint256 和 int256的別名
操作符:
比較 : <=,<,==,!=,>=,> (計算布爾量)
位操作符: &,|,^(位異或),~(位取反)
地址: 20字節(jié)(一個??Ethereum地址),地址的類型也可以有成員(請看地址功能?(#functions-on-addresses))? 作為所有合約的base
操作符:
地址成員:
若查詢到有資產(chǎn)余額的地址,然后發(fā)送? Ether(以wei為單位) 到send 函數(shù)的地址上
address?x?=?0x123;
address?myAddress?=?this;
if?(x.balance?<?10?&&?myAddress.balance?>=?10) x.send(10);
如果x是合約地址,它的代碼(特別的指出 如果有回退函數(shù),) 將和send 調(diào)用一起執(zhí)行(這是EVM的限制,不能修改) 如果用完了gas或者失敗,Ether轉(zhuǎn)移將被回退,這種情況下,send返回false
另外,和合約的接口不是附在ABI 上,函數(shù)調(diào)用可以引用任意數(shù)量的參數(shù),這些參數(shù)要填補成32字節(jié),并被拼接。一個例外的情況是第一個參數(shù)被確切的編碼成4字節(jié),這種情況下,不用填補,直接使用函數(shù)符號
address?nameReg?=?0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
nameReg.call("register", "MyName");
nameReg.call(bytes4(sha3("fun(uint256)")), a);
函數(shù)調(diào)用返回了一個布爾值,表示函數(shù)是否是正常調(diào)用結(jié)束(true)或引起了EVM異常(false)。不可能訪問返回實際數(shù)據(jù)(這個我們需要提前知道編碼和大小)。
同樣,可以使用函數(shù)callcode:不同之處在于,只使用給定地址的編碼,所有其他方面(存儲、余額…)取自于當(dāng)前的合約。callcode的目的是使用庫代碼存儲在另一個合同。用戶必須確保存儲在兩個合約的布局適用于callcode。
call和callcode是非常低級的函數(shù),它可以作為打破Solidity的類型安全的最后手段。
所有合同繼承成員地址,所以可以使用this.balance查詢當(dāng)前合約的余額。
Fixed-size byte arrays
bytes1, bytes2, bytes3, ..., bytes32. byte is an alias for bytes1.
Operators:
Comparisons: <=, <, ==, !=, >=, > (evaluate to bool)
固定大小的字節(jié)數(shù)組
bytes1, bytes2, bytes3, ..., bytes32. byte 都是 bytes1的別名.
操作符:
比較符?: <=, <, ==, !=, >=, > (布爾的評估)
動態(tài)分配大小字節(jié)數(shù)組:
bytes:動態(tài)分配大小字節(jié)數(shù)組,參看 Arrays,不是一個值類型!
string:動態(tài)大小UTF8編碼的字符串,參看Arrays。不是一個值類型!
????? 作為一個常識, 使用bytes來表示任意長度原始字節(jié)數(shù)據(jù),使用string來表示特定長度字符串?dāng)?shù)據(jù)(utf - 8編碼)。如果你想限定特定數(shù)量的字節(jié)長度, 就使用bytes1 到 bytes32,? 因為這樣占用的存儲空間更少。
整型常量是特定精度整數(shù),它們也可以和非常量同時使用。例如, var x = 1 - 2;? 1 - 2的值是-1,然后賦值給x, 這時x接收類型為int8——最小的類型,其中包含-1, 雖然1和2的類型實際上是uint8。
有時最大超過256位的整型常量也可用于計算:var x =(0 xffffffffffffffffffff 0 xffffffffffffffffffff) 0;這里,x的值是0,它的類型是uint8類型。
字符串常量用兩個雙引號括起來(“abc”)。和整型常量相比,字符串常量有些不同,字符串常量可以隱式轉(zhuǎn)換成bytes ???? 如果合適,可以是bytes,也可以是string。
contract?test {
????enum?ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
??? ActionChoices choice;
??? ActionChoices?constant?defaultChoice?=?ActionChoices.GoStraight;
????function?setGoStraight()
??? {
??????? choice?=?ActionChoices.GoStraight;
??? }
枚舉是一種Solidity中的創(chuàng)建一個用戶定義的類型。枚舉類型中的枚舉值可顯式轉(zhuǎn)換,但從整數(shù)類型隱式轉(zhuǎn)換是不允許的。
contract?test {
????enum?ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
??? ActionChoices choice;
??? ActionChoices?constant?defaultChoice?=?ActionChoices.GoStraight;
????function?setGoStraight()
??? {
??????? choice?=?ActionChoices.GoStraight;
??? }
????// Since enum types are not part of the ABI, the signature of "getChoice"
????// will automatically be changed to "getChoice() returns (uint8)"
????// for all matters external to Solidity. The integer type used is just
????// large enough to hold all enum values, i.e. if you have more values,
????// `uint16` will be used and so on.
/ /因為枚舉類型不是ABI的一部分,“getChoice”的符號
/ /將自動改為“getChoice()返回(uint8)”
/ /從Solidity外部看,使用的整數(shù)類型
/ /足夠容納所有枚舉值,但如果你有更多的值,
/ /“uint16”將使用。
????function?getChoice()?returns?(ActionChoices)
??? {
????????return?choice;
??? }
????function?getDefaultChoice()?returns?(uint)
??? {
????????return?uint(defaultChoice);
??? }}
復(fù)雜類型,例如類型并不總是適合256位,比我們已經(jīng)看到的值類型更復(fù)雜的類型,必須更仔細(xì)地處理。因為復(fù)制拷貝他們可能相當(dāng)耗費存儲和時間,? 我們必須考慮把它們存儲在內(nèi)存(這不是持久化)或者存儲器(狀態(tài)變量存放的地方)。
每一個復(fù)雜類型,即數(shù)組和結(jié)構(gòu)體,有一個額外的注解,“數(shù)據(jù)位置”,不管它是存儲在內(nèi)存中,還是存儲在存儲器上。根據(jù)上下文,總是有一個默認(rèn)的,但它可以通過附加存儲或內(nèi)存覆蓋類型。函數(shù)參數(shù)的默認(rèn)值(包括返回參數(shù))是在內(nèi)存上,局部變量的默認(rèn)存儲位置是在存儲器上。存儲器上存有狀態(tài)變量(很明顯)。
(除了內(nèi)存,存儲器這兩個位置之外),還有第三個數(shù)據(jù)位置,“calldata”,這是一個?無法改變的,非持久的?存儲函數(shù)參數(shù)的地方。外部函數(shù)的函數(shù)參數(shù)(不返回參數(shù))“calldata”,其在形式上象內(nèi)存。
數(shù)據(jù)位置很重要,因為它們改變賦值方式:在存儲和內(nèi)存以及狀態(tài)變量之間賦值(甚至從其他狀態(tài)變量)總是創(chuàng)建一個獨立的副本。賦值只分配一個本地存儲變量引用,這總是指向狀態(tài)變量的引用,后者同時改變。另一方面,從一個內(nèi)存存儲引用類型, 賦值到另一個內(nèi)存存儲引用類型,(這時)并不創(chuàng)建一個副本。
contract?c {
??uint[] x;?// the data location of x is storage
??// the data location of memoryArray is memory
??function?f(uint[] memoryArray) {
??? x?=?memoryArray;?// works, copies the whole array to storage
????var?y?=?x;?// works, assigns a pointer, data location of y is storage
??? y[7];?// fine, returns the 8th element
??? y.length?=?2;?// fine, modifies x through y
????delete?x;?// fine, clears the array, also modifies y
????// The following does not work; it would need to create a new temporary /
????// unnamed array in storage, but storage is "statically" allocated:
????// y = memoryArray;
????// This does not work either, since it would "reset" the pointer, but there
????// is no sensible location it could point to.
????// delete y;
??? g(x);?// calls g, handing over a reference to x
??? h(x);?// calls h and creates an independent, temporary copy in memory
? }
??function?g(uint[]?storage?storageArray)?internal?{}
??function?h(uint[] memoryArray) {}}
contract?c {
??uint[] x;?// the data location of x is storage????x的數(shù)據(jù)位置是存儲器
??// the data location of memoryArray is memory??memoryArray的數(shù)據(jù)位置是內(nèi)存
??function?f(uint[] memoryArray) {
??? x?=?memoryArray;?// works, copies the whole array to storage??運行,拷貝整個數(shù)組到存儲器
????var?y?=?x;?// works, assigns a pointer, data location of y is storage?運行,賦值到一個指針,y的數(shù)據(jù)位置是存儲器
??? y[7];?// fine, returns the 8th element?好了,返回第8個元素
??? y.length?=?2;?// fine, modifies x through y????好了,通過y改變x
????delete?x;?// fine, clears the array, also modifies y??好了,清除數(shù)組,也改變y
????// The following does not work; it would need to create a new temporary /??以下代碼不起作用, 它是在存儲中創(chuàng)立一個臨時的未命名的數(shù)組,但存儲器是“靜態(tài)”分配的
????// unnamed array in storage, but storage is "statically" allocated:
????// y = memoryArray;
????// This does not work either, since it would "reset" the pointer, but there?這個也不起作用,因為 它重置了指針, 但已經(jīng)沒有相應(yīng)的位置可以指向
????// is no sensible location it could point to.
????// delete y;
??? g(x);?// calls g, handing over a reference to x???調(diào)用g(x)? 將x作為引用
??? h(x);?// calls h and creates an independent, temporary copy in memory?調(diào)用h(x). 在內(nèi)存中創(chuàng)立了一個獨立的,暫時的拷貝
? }
??function?g(uint[]?storage?storageArray)?internal?{}
??function?h(uint[] memoryArray) {}}
強制數(shù)據(jù)位置:
外部函數(shù)的參數(shù)(不返回):calldata
默認(rèn)數(shù)據(jù)位置:
函數(shù)(有返回)的參數(shù):內(nèi)存
數(shù)組是可以在編譯時固定大小的,也可以是動態(tài)的。對于存儲器數(shù)組來說,成員類型可以是任意的(也可以是其他數(shù)組,映射或結(jié)構(gòu))。對于內(nèi)存數(shù)組來說 ,成員類型不能是一個映射;如果是公開可見的函數(shù)參數(shù),成員類型是必須是ABI類型的。
固定大小k的數(shù)組和基本類型T,可以寫成T[k],? 動態(tài)數(shù)組寫成 T[ ] 。例如, 有5個基本類型為uint 的動態(tài)數(shù)組的數(shù)組 可以寫成uint[ ][5]? ( 注意,和一些其他語言相比,這里的符號表示次序是反過來的)。為了訪問第三動態(tài)數(shù)組中的第二個uint, 必須使用x[2][1](下標(biāo)是從零開始的,訪問模式和聲明模式正好相反, 即x[2]是從右邊剔除了一階)。
bytes和?string?是特殊類型的數(shù)組。?bytes?類似于byte[ ],但它是緊湊排列在calldata里的。string?等于?bytes ,?但不允許用長度或所以索引訪問(現(xiàn)在情況是這樣的)。
所以bytes應(yīng)該優(yōu)先于byte[ ],因為它效率更高。
請注意
如果你想訪問字符串s的某個字節(jié),? 要使用 bytes(s).length/bytes(s)[7]= ' x ';。記住,你正在訪問的低級utf - 8字節(jié)表示,而不是單個字符!
成員(函數(shù)):
length: 總有 一個稱作length的成員(函數(shù))來存放元素的數(shù)量。動態(tài)數(shù)組可以通過改變.length成員(函數(shù)),在存儲器里來調(diào)整大小(不是在內(nèi)存中)。當(dāng)試圖訪問現(xiàn)有長度之外的成員時,這并不是自動被許可的。(數(shù)組)一旦創(chuàng)建,內(nèi)存里的數(shù)組大小是固定的(如果是動態(tài)的數(shù)組,則取決于運行時參數(shù))。
push?:動態(tài)存儲數(shù)組arrays和字節(jié)bytes(不是字符串string)有一個成員函數(shù)稱作push,可在數(shù)組的尾部添加一個元素。函數(shù)返回新的長度。
警告
到目前為止,還不可以在外部函數(shù)中使用數(shù)組的數(shù)組。
警告
由于EVM的局限,不可能從外部函數(shù)調(diào)用返回的動態(tài)內(nèi)容。合約函數(shù)f contract C { function f() returns (uint[]) { ... } }? 使用web3.js調(diào)用,將有返回值,? 但使用Solidity調(diào)用,就沒有返回值。
現(xiàn)在唯一的解決方法是使用較大的靜態(tài)尺寸大小的數(shù)組。
contract?ArrayContract {
??uint[2*\*20] m_aLotOfIntegers;
??// Note that the following is not a pair of arrays but an array of pairs.
??bool[2][] m_pairsOfFlags;
??// newPairs is stored in memory - the default for function arguments
??function?setAllFlagPairs(bool[2][] newPairs) {
????// assignment to a storage array replaces the complete array
??? m_pairsOfFlags?=?newPairs;
? }
??function?setFlagPair(uint?index,?bool?flagA,?bool?flagB) {
????// access to a non-existing index will throw an exception
??? m_pairsOfFlags[index][0]?=?flagA;
??? m_pairsOfFlags[index][1]?=?flagB;
? }
??function?changeFlagArraySize(uint?newSize) {
????// if the new size is smaller, removed array elements will be cleared
??? m_pairsOfFlags.length?=?newSize;
? }
??function?clear() {
????// these clear the arrays completely
????delete?m_pairsOfFlags;
????delete?m_aLotOfIntegers;
????// identical effect here
??? m_pairsOfFlags.length?=?0;
? }
??bytes?m_byteData;
??function?byteArrays(bytes?data) {
????// byte arrays ("bytes") are different as they are stored without padding,
????// but can be treated identical to "uint8[]"
??? m_byteData?=?data;
??? m_byteData.length?+=?7;
??? m_byteData[3]?=?8;
????delete?m_byteData[2];
? }
??function?addFlag(bool[2] flag)?returns?(uint) {
????return?m_pairsOfFlags.push(flag);
? }
??function?createMemoryArray(uint?size)?returns?(bytes) {
????// Dynamic memory arrays are created using `new`:
????uint[2][]?memory?arrayOfPairs?=?new?uint[2][](size);
????// Create a dynamic byte array:
????bytes?memory?b?=?new?bytes(200);
????for?(uint?i?=?0; i?<?b.length; i++)
????? b[i]?=?byte(i);
????return?b;
? }}
contract?ArrayContract {
??uint[2\20] m_aLotOfIntegers;
??// Note that the following is not a pair of arrays but an array of pairs.?注意下面不是兩個數(shù)組,而是一個數(shù)組,該數(shù)組的成員是一對值
??bool[2][] m_pairsOfFlags;
??// newPairs is stored in memory - the default for function arguments??newPairs在內(nèi)存中存儲-這是函數(shù)參數(shù)的缺省方式
??function?setAllFlagPairs(bool[2][] newPairs) {
????// assignment to a storage array replaces the complete array?賦值到一個存儲器數(shù)組里以替換整個數(shù)組
??? m_pairsOfFlags?=?newPairs;
? }
??function?setFlagPair(uint?index,?bool?flagA,?bool?flagB) {
????// access to a non-existing index will throw an exception
??? m_pairsOfFlags[index][0]?=?flagA;
??? m_pairsOfFlags[index][1]?=?flagB;
? }
??function?changeFlagArraySize(uint?newSize) {
????// if the new size is smaller, removed array elements will be cleared??如果新的尺寸太小,則已經(jīng)移除的元素將被清除
??? m_pairsOfFlags.length?=?newSize;
? }
??function?clear() {
????// these clear the arrays completely
????delete?m_pairsOfFlags;
????delete?m_aLotOfIntegers;
????// identical effect here
??? m_pairsOfFlags.length?=?0;
? }
??bytes?m_byteData;
??function?byteArrays(bytes?data) {
????// byte arrays ("bytes") are different as they are stored without padding,??如果沒有填充的話,字節(jié)數(shù)組("bytes")和存儲時是不同的
????// but can be treated identical to "uint8[]"??但可以轉(zhuǎn)換成 "uint8[]"
??? m_byteData?=?data;
??? m_byteData.length?+=?7;
??? m_byteData[3]?=?8;
????delete?m_byteData[2];
? }
??function?addFlag(bool[2] flag)?returns?(uint) {
????return?m_pairsOfFlags.push(flag);
? }
??function?createMemoryArray(uint?size)?returns?(bytes) {
????// Dynamic memory arrays are created using `new`:?使用`new`創(chuàng)立動態(tài)內(nèi)存數(shù)組
????uint[2][]?memory?arrayOfPairs?=?new?uint[2][](size);
????// Create a dynamic byte array:??創(chuàng)立動態(tài) byte 數(shù)組
????bytes?memory?b?=?new?bytes(200);
????for?(uint?i?=?0; i?<?b.length; i++)
????? b[i]?=?byte(i);
????return?b;
? }}
Solidity 提供了一種方法來定義新類型的形式結(jié)構(gòu),如下面的例子所示:
contract?CrowdFunding {
??// Defines a new type with two fields.
??struct?Funder {
????address?addr;
????uint?amount;
? }
??struct?Campaign {
????address?beneficiary;
????uint?fundingGoal;
????uint?numFunders;
????uint?amount;
????mapping?(uint?=>?Funder) funders;
? }
??uint?numCampaigns;
??mapping?(uint?=>?Campaign) campaigns;
??function?newCampaign(address?beneficiary,?uint?goal)?returns?(uint?campaignID) {
??? campaignID?=?numCampaigns++;?// campaignID is return variable
????// Creates new struct and saves in storage. We leave out the mapping type.
??? campaigns[campaignID]?=?Campaign(beneficiary, goal, 0, 0);
? }
??function?contribute(uint?campaignID) {
??? Campaign c?=?campaigns[campaignID];
????????// Creates a new temporary memory struct, initialised with the given values
????????// and copies it over to storage.
????????// Note that you can also use Funder(msg.sender, msg.value) to initialise.
??? c.funders[c.numFunders++]?=?Funder({addr:?msg.sender, amount:?msg.value});
??? c.amount?+=?msg.value;
? }
??function?checkGoalReached(uint?campaignID)?returns?(bool?reached) {
??? Campaign c?=?campaigns[campaignID];
????if?(c.amount?<?c.fundingGoal)
??????return?false;
??? c.beneficiary.send(c.amount);
??? c.amount?=?0;
????return?true;
? }}
contract?CrowdFunding {
??// Defines a new type with two fields.?定義了兩個域的新類型
??struct?Funder {
????address?addr;
????uint?amount;
? }
??struct?Campaign {
????address?beneficiary;
????uint?fundingGoal;
????uint?numFunders;
????uint?amount;
????mapping?(uint?=>?Funder) funders;
? }
??uint?numCampaigns;
??mapping?(uint?=>?Campaign) campaigns;
??function?newCampaign(address?beneficiary,?uint?goal)?returns?(uint?campaignID) {
??? campaignID?=?numCampaigns++;?// campaignID is return variable??campaignID是返回的變量
????// Creates new struct and saves in storage. We leave out the mapping type.?創(chuàng)建一個新的結(jié)構(gòu)體,保存在存儲器里, 保留了映射類型
??? campaigns[campaignID]?=?Campaign(beneficiary, goal, 0, 0);
? }
??function?contribute(uint?campaignID) {
??? Campaign c?=?campaigns[campaignID];
????????// Creates a new temporary memory struct, initialised with the given values?創(chuàng)建了一個新的臨時內(nèi)存結(jié)構(gòu)體,用給定的值進(jìn)行初始化
????????// and copies it over to storage.?拷貝到存儲器上
????????// Note that you can also use Funder(msg.sender, msg.value) to initialise.?注意你可以使用 Funder(msg.sender, msg.value)來初始化
??? c.funders[c.numFunders++]?=?Funder({addr:?msg.sender, amount:?msg.value});
??? c.amount?+=?msg.value;
? }
??function?checkGoalReached(uint?campaignID)?returns?(bool?reached) {
??? Campaign c?=?campaigns[campaignID];
????if?(c.amount?<?c.fundingGoal)
??????return?false;
??? c.beneficiary.send(c.amount);
??? c.amount?=?0;
????return?true;
? }}
此(例子)合約沒有提供眾籌合約的完整功能,? 但它包含了必要的基本概念,以便(讓我們更好地)理解結(jié)構(gòu)體。結(jié)構(gòu)體類型可以是內(nèi)部映射或者是數(shù)組,他們本身也可以包含映射和數(shù)組。
通常這是不可能,即一個結(jié)構(gòu)體包含一個自身類型的成員, 雖然結(jié)構(gòu)體本身可以是一個映射的值類型成員。這個限制是必要的, 原因是結(jié)構(gòu)體的大小是有限的。
注意所有的函數(shù)中, 結(jié)構(gòu)類型是賦值給一個局部變量(默認(rèn)存儲數(shù)據(jù)的位置)。這并不復(fù)制結(jié)構(gòu)體,僅僅保存了一個引用, 本地變量的賦值最終還是以寫進(jìn)了狀態(tài)中。
當(dāng)然,您也可以直接訪問結(jié)構(gòu)體的成員變量,而不用賦值到一個局部變量,如campaigns[campaignID].amount = 0.
映射類型被聲明為 mapping _KeyType => _ValueType,? _KeyType可以是除了映射以外的其他任何類型,_ValueType可以是任何類型,包括映射。
映射可以被視為初始化的散列表,這樣每一個鍵值都存在, 這些鍵值在字節(jié)表示上是全零。相似性到此為止,盡管:key數(shù)據(jù)實際上并不是存儲在一個映射中,它只有在使用sha3哈希查找值使用。
因此,映射沒有長度,也沒有一個鍵或值的被“set”的概念。
映射是只允許為狀態(tài)變量(在內(nèi)部函數(shù)中作為一個存儲引用類型)。
如果是一個左值操作(即一個可以賦值給它的變量),可以使用以下的操作符:
a += e相當(dāng)于 a = a + e。操作符- = * =,/ = % = | = & = ^ = 都有相應(yīng)的定義。a++和a--相當(dāng)于a+ = 1 /a - = 1,但是表達(dá)式本身還有一個操作前的值。相比之下, --a和++a有相同的影響但返回值改變。
刪除一個指定類型的初始值為整數(shù),即相當(dāng)于a= 0,但是它也可以用于數(shù)組,它分配一個動態(tài)數(shù)組的長度為零或一個靜態(tài)數(shù)組長度相同的所有元素重置。對于結(jié)構(gòu)體,它分配一個struct,重置所有成員。
刪除沒有影響整體映射(如映射的鍵可能是任意的,通常是未知的)。如果你刪除一個結(jié)構(gòu),它將重置沒有映射的所有成員,也可以是遞歸的成員,除非它們映射。然而,個別鍵和他們的映射是可以刪除。
重要的是要注意,刪除一個a的賦值,? 即它存儲在一個新的對象。
contract?DeleteExample {
??uint?data;
??uint[] dataArray;
??function?f() {
????uint?x?=?data;
????delete?x;?// sets x to 0, does not affect data
????delete?data;?// sets data to 0, does not affect x which still holds a copy
????uint[] y?=?dataArray;
????delete?dataArray;?// this sets dataArray.length to zero, but as uint[] is a complex object, also
????// y is affected which is an alias to the storage object
????// On the other hand: "delete y" is not valid, as assignments to local variables
????// referencing storage objects can only be made from existing storage objects.
? }}
contract?DeleteExample {
??uint?data;
??uint[] dataArray;
??function?f() {
????uint?x?=?data;
????delete?x;?// sets x to 0, does not affect data? 設(shè)置x為0, 不影響data
????delete?data;?// sets data to 0, does not affect x which still holds a copy? 設(shè)置data為0,x不受影響,x仍然有一個拷貝
????uint[] y?=?dataArray;
????delete?dataArray;?// this sets dataArray.length to zero, but as uint[] is a complex object, also?dataArray.length長度是0。但是uint[ ]是一個復(fù)雜對象, y受影響,其是存儲對象的別名
????// y is affected which is an alias to the storage object
????// On the other hand: "delete y" is not valid, as assignments to local variables?另外, "delete y"是非法的,因為y是賦值到本地變量
????// referencing storage objects can only be made from existing storage objects.引用存儲對象僅僅來自于現(xiàn)有的存儲對象
? }}
如果一個操作符應(yīng)用于不同類型,? 編譯器(就會)試圖隱式把操作數(shù)的類型,從一種類型轉(zhuǎn)換到其他類型(賦值也是如此)。一般來說,一個隱式的值類型之間的轉(zhuǎn)換是可能的,如果是語義敏感的話,信息不會丟失:unt8可轉(zhuǎn)換成uint16, int128, int256,? 但int8不能轉(zhuǎn)換成uint256(因為uint256放不下? 如 -1)。此外,無符號整數(shù)可以轉(zhuǎn)換成相同或更大的尺寸的bytes ,? 但反過來,不行 。任何類型都可以轉(zhuǎn)化為uint160,也可以轉(zhuǎn)換為地址。
如果編譯器不允許隱式轉(zhuǎn)換,但你知道你在做什么,一個顯式的類型轉(zhuǎn)換有時是可能的:
int8 y = 3;
uint x =uint(y);
這個代碼片段結(jié)尾 , x的值是 0xfffff . .fd(64個十六進(jìn)制字符),-3在256位的二進(jìn)制補碼表示。
如果一個類型是顯式地轉(zhuǎn)換為一個更小的類型,高階位將被移除。
uint32 = 0x12345678;
uint16 b = uint16(a);/ /?*b will be 0x5678 now*??*b現(xiàn)在變成了0x5678,(少了1234)*
為方便起見,它并不總是必須顯式地指定一個變量的類型,編譯器會自動從第一個賦值表達(dá)式的變量類型里推斷出新變量的類型:
uint20 x = 0 x123;
var y = x;
在這里,y的類型是uint20。在函數(shù)參數(shù)或返回參數(shù)是不可能使用var(這個關(guān)鍵字)的。
警告
這個類型僅僅是從第一次賦值推導(dǎo)得出的,所以以下代碼片段的循環(huán)是無限的,? 因為 i 的類型是uint8, 這種類型的任何值都小于2000。for (var i = 0;< 2000;i+ +){…}
Next??Previous
? Copyright 2015, Ethereum. Revision 9b9d10b4.
Built with?Sphinx?using a?theme?provided by?Read the Docs.
?Read the Docsv: latest?