solidity語法:表達式和控制結構

表達式和控制結構

控制結構

除了 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異常自動發生,有三種狀況, :

  1. 若是你訪問數組超出其長度 (即x[i] where i >= x.length)

  2. 若是一個經過消息調用的函數沒有正確的執行結束(即gas用完,或自己拋出異常)。

  3. 若是一個庫裏不存在的函數被調用,或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開發,能夠訪問匯智網提供的最熱門在線互動教程:

其餘更多內容也能夠訪問這個以太坊博客

相關文章
相關標籤/搜索