除了 switch和goto,solidity的絕大多數控制結構均來自於C / JavaScript,if, else, while, for, break, continue, return, ? :, 的語義均和C / JavaScript同樣。git
條件語句中的括號不能省略,但在單條語句先後的花括號能夠省略。github
注意,(Solidity中 )沒有象C和JavaScrip那樣 ,從非布爾類型類型到布爾類型的轉換, 因此if (1){…}不是合法的Solidity(語句)。數組
內部函數調用安全
當前合約和函數能夠直接調用(「內部」),也能夠遞歸, 因此你會看到在這個「荒謬」的例子:ide
contract c { function g(uint a) returns (uint ret) { return f(); } function f() returns (uint ret) { return g(7) + f(); }}
這些函數調用在EMV裏翻譯成簡單的jumps 語句。當前內存沒有被清除, 即經過內存引用的函數是很是高效的。僅僅同一個合約的函數可在內部被調用。函數
外部函數調用學習
表達式this.g(8);也是一個合法的函數調用, 可是這一次,這個函數將被稱爲「外部」的, 經過消息調用,而不是直接經過jumps調用。其餘合約的函數也是外部調用。對於外部調用,全部函數參數必須被複制到內存中。區塊鏈
當調用其餘合約的函數時, 這個調用的wei的數量被髮送和gas被定義:ui
contract InfoFeed { function info() returns (uint ret) { return 42; } } contract Consumer { InfoFeed feed; function setFeed(address addr) { feed = InfoFeed(addr); } function callFeed() { feed.info.value(10).gas(800)(); } }
注意:表達式InfoFeed(addr)執行顯式的類型轉換, 意思是「咱們知道給定的地址的合約類型是InfoFeed」, 這並不執行構造函數。 咱們也能夠直接使用函數setFeed(InfoFeed _feed) { feed = _feed; }。 注意: feed.info.value(10).gas(800)是(本地)設置值和函數調用發送的gas數量, 只有最後的括號結束後才完成實際的調用。this
有參數的函數調用能夠有名字,不使用參數的名字(特別是返回參數)能夠省略。
contract c { function f(uint key, uint value) { ... } function g() { // named arguments 具名參數 f({value: 2, key: 3}); } // omitted parameters 省略名字的參數 function func(uint k, uint) returns(uint) { return k; } }
表達式的計算順序是不肯定的(準確地說是, 順序表達式樹中的子節點表達式計算順序是不肯定的的, 但他們對節點自己,計算表達式順序固然是肯定的)。只保證語句執行順序,以及布爾表達式的短路規則。
析構賦值並返回多個值
Solidity內部容許元組類型,即一系列的不一樣類型的對象的大小在編譯時是一個常量。這些元組能夠用來同時返回多個值,而且同時將它們分配給多個變量(或左值運算)
contract C { uint[] data; function f() returns (uint, bool, uint) { return (7, true, 2); } function g() { // Declares and assigns the variables. Specifying the type explicitly is not possible. var (x, b, y) = f(); // Assigns to a pre-existing variable. (x, y) = (2, 7); // Common trick to swap values -- does not work for non-value storage types. (x, y) = (y, x); // Components can be left out (also for variable declarations). // If the tuple ends in an empty component, // the rest of the values are discarded. (data.length,) = f(); // Sets the length to 7 // The same can be done on the left side. (,data[3]) = f(); // Sets data[3] to 2 // Components can only be left out at the left-hand-side of assignments, with // one exception: (x,) = (1,); // (1,) is the only way to specify a 1-component tuple, because (1) is // equivalent to 1. } } contract C { uint[] data; function f() returns (uint, bool, uint) { return (7, true, 2); } function g() { // Declares and assigns the variables. Specifying the type explicitly is not possible. 聲明和賦值變量,沒必要顯示定義類型 var (x, b, y) = f(); // Assigns to a pre-existing variable. 賦值給已經存在的變量 (x, y) = (2, 7); // Common trick to swap values -- does not work for non-value storage types. 交換值的技巧-對非值存儲類型不起做用 (x, y) = (y, x); // Components can be left out (also for variable declarations). 元素可排除(對變量聲明也適用) // If the tuple ends in an empty component, 若是元組是以空元素爲結尾 // the rest of the values are discarded. 值的其他部分被丟棄 (data.length,) = f(); // Sets the length to 7 設定長度爲7 // The same can be done on the left side. 一樣能夠在左側作 (,data[3]) = f(); // Sets data[3] to 2 將data[3] 設爲2 // Components can only be left out at the left-hand-side of assignments, with // one exception: 組件只能在賦值的左邊被排除,有一個例外 (x,) = (1,); // (1,) is the only way to specify a 1-component tuple, because (1) is (1,)是定義一個元素的元組,(1)是等於1 // equivalent to 1. }}
對於象數組和結構體這樣的非值類型,賦值的語義更復雜些。賦值到一個狀態變量老是須要建立一個獨立的副本。另外一方面,對基本類型來講,賦值到一個局部變量須要建立一個獨立的副本, 即32字節的靜態類型。若是結構體或數組(包括字節和字符串)從狀態變量被賦值到一個局部變量, 局部變量則保存原始狀態變量的引用。第二次賦值到局部變量不修改狀態,只改變引用。賦值到局部變量的成員(或元素)將改變狀態。
有一些自動拋出異常的狀況(見下文)。您可使用throw 指令手動拋出一個異常。異常的影響是當前執行的調用被中止和恢復(即全部狀態和餘額的變化均沒有發生)。另外, 異常也能夠經過Solidity 函數 「冒出來」, (一旦「異常」發生, 就send "exceptions", call和callcode底層函數就返回false)。
捕獲異常是不可能的。
在接下來的例子中,咱們將演示如何輕鬆恢復一個Ether轉移,以及如何檢查send的返回值:
contract Sharer { function sendHalf(address addr) returns (uint balance) { if (!addr.send(msg.value/2)) throw; // also reverts the transfer to Sharer return this.balance; } } contract Sharer { function sendHalf(address addr) returns (uint balance) { if (!addr.send(msg.value/2)) throw; // also reverts the transfer to Sharer 也恢復Sharer的轉移 return this.balance; } }
目前,Solidity異常自動發生,有三種狀況, :
若是你訪問數組超出其長度 (即x[i] where i >= x.length)
若是一個經過消息調用的函數沒有正確的執行結束(即gas用完,或自己拋出異常)。
若是一個庫裏不存在的函數被調用,或Ether被髮送到一個函數庫裏。
在內部,當拋出異常時 ,Solidity就執行「非法jump」, 從而致使EMV(Ether虛擬機)恢復全部更改狀態。這個緣由是沒有安全的方法能夠繼續執行, 預期的結果沒有發生。因爲咱們想保留事務的原子性,(因此)最安全的作法是恢復全部更改,並使整個事務(或者至少調用)沒有受影響。
© Copyright 2015, Ethereum. Revision 37381072.
Built with Sphinx using a theme provided by Read the Docs.
Read the Docsv: latest
若是你但願高效的學習以太坊DApp開發,能夠訪問匯智網提供的最熱門在線互動教程:
其餘更多內容也能夠訪問這個以太坊博客。