Solidity的自定義結(jié)構(gòu)體深入詳解(十一)|入門系列

結(jié)構(gòu)體,Solidity中的自定義類型烤礁。我們可以使用Solidity的關(guān)鍵字struct來進行自定義讼积。結(jié)構(gòu)體內(nèi)可以包含字符串,整型等基本數(shù)據(jù)類型脚仔,以及數(shù)組勤众,映射,結(jié)構(gòu)體等復雜類型鲤脏。數(shù)組们颜,映射,結(jié)構(gòu)體也支持自定義的結(jié)構(gòu)體猎醇。我們來看一個自定義結(jié)構(gòu)體的定義:

pragma solidity ^0.4.0;

contract SimpleStruct{
  //學生
  struct Student{
    string name;
    int num;
  }

  //班級
  struct Class{
    string clsName;
    //學生的列表
    Student[] students;
    mapping(string=>Student)index;
  }
}

在上面的代碼中窥突,我們定義了一個簡單的結(jié)構(gòu)體Student,它包含一些基本的數(shù)據(jù)類型硫嘶。另外我們還定義了一個稍微復雜一點的結(jié)構(gòu)體Class阻问,它包含了其它結(jié)構(gòu)體Student,以及數(shù)組沦疾,映射等類型称近。

數(shù)組類型的students和映射類型的index的聲明中還使用了結(jié)構(gòu)體。

1.1 結(jié)構(gòu)體定義的限制

我們不能在結(jié)構(gòu)中定義一個自己作為類型哮塞,這樣限制原因是刨秆,自定義類型的大小不允許是無限的。我們來看看下述的代碼:

pragma solidity ^0.4.0;

contract NoMemberOfOwn{
  struct A{
    //定義包含自己的會報錯
    //Error: Recursive struct definition.
    //A a;
    
    mapping(int=>A) mappingMemberOfOwn;
    
    A[] arrayMemberOfOwn;
  }
}

在上面的代碼中彻桃,我們嘗試在A類型中定義一個A a;坛善,將會報錯Error: Recursive struct definition.。雖然如此邻眷,但我們?nèi)匀荒茉陬愋蛢?nèi)用數(shù)組眠屎,映射來引用當前定義的類型,如變量mappingMemberOfOwn肆饶,arrayMemberOfOwn所示改衩。

2. 初始化

下面我們來說說結(jié)構(gòu)體的初始化。

2.1 直接初始化

如果我們聲明的自定義類型為A驯镊,我們可以使用A(變量1,變量2, ...)的方式來完成初始化葫督。來看下面的代碼:

pragma solidity ^0.4.0;

contract StructInitial{
  struct A{
    string name;
    mapping(address=>A) map;
    int age;
    string[] cources;
  }

  function init() returns (string, int, string){
    string[] memory cources = new string[](1);
    cources[0] = "Chemistry";

    //按順序填值,初始化時竭鞍,可以跳過映射類型
    A memory a = A("Jack", 23, cources);

    return (a.name, a.age, cources[0]);
  }
}

上面的代碼中,我們按定義依次填入值橄镜,即可完成了初始化偎快。需要注意的是,參數(shù)要與定義的數(shù)量匹配洽胶。當你填的參數(shù)與預計初始化的參數(shù)不一致時晒夹,會提示Error: Wrong argument count for function call: 2 arguments given but expected 3. Members that have to be skipped in memory: map。另外姊氓,在初始化時丐怯,需要忽略映射類型[1],后面有具體說明翔横。

2.2 命名初始化

還可以使用類似JavaScript的命名參數(shù)初始化的方式读跷,通過傳入?yún)?shù)名和對應(yīng)值的對象。這樣做的好處在于可以不按定義的順序傳入值禾唁。我們來看看下面的例子:

pragma solidity ^0.4.0;

contract StructNamedInitial{
  struct Student{
    string name;
    mapping(address=>Student) map;
    int age;
    string[] cources;
  }

  function init() returns (string, int, string){
    string[] memory crs = new string[](1);
    crs[0] = "Chemistry";

    //按命名參數(shù)的方式進行初始化
    Student memory s = Student({
        age : 10,
        name : "Jack",
        cources: crs
      });

    return (s.name, s.age, s.cources[0]);
  }
}

上面的例子中效览,通過在參數(shù)對象中,指定鍵為對應(yīng)的參數(shù)名蟀俊,值為你想要初化的值钦铺,我們即完成了初始化。同樣需要注意的是肢预,參數(shù)要與定義的個數(shù)一致矛洞,否則會報類似這樣的錯誤Error: Wrong argument count for function call: 2 arguments given but expected 3. Members that have to be skipped in memory: map。另外烫映,在初始化時沼本,需要忽略映射類型[1],后面有具體說明锭沟。

2.3 結(jié)構(gòu)體中映射的初始化

由于映射是一種特殊的數(shù)據(jù)結(jié)構(gòu)[2]抽兆。

Mappings can be seen as hashtables which are virtually initialized such that every possible key exists and is mapped to a value whose byte-representation is all zeros: a type’s default value. The similarity ends here, though: The key data is not actually stored in a mapping, only its keccak256 hash used to look up the value.

Because of this, mappings do not have a length or a concept of a key or value being “set”.

可以你可能只能在storage變量中使用它。

pragma solidity ^0.4.0;

contract StructMappingInitial{
  struct A{
    string name;
    mapping(address=>A) map;
    int age;
    string[] cources;
  }

  //分配映射的空間
  A storageVar;

  function init() returns (string, int, string){
    string[] memory cources = new string[](1);
    cources[0] = "Chemistry";

    A memory a = A("Jack", 23, cources);

    storageVar = a;
    storageVar.map[msg.sender] = a;

    return (a.name, a.age, cources[0]);
  }
}

上面的例子中族淮,我們定義的了一個storage的狀態(tài)變量storageVar辫红,完成了映射類型的存儲空間分配。然后我們就能對映射類型賦值了祝辣。

如果你嘗試對memory的映射類型賦值贴妻,會報錯Error: Member "map" is not available in struct StructMappingInitial.A memory outside of storage.

3. 結(jié)構(gòu)體的可見性

關(guān)于可見性蝙斜,當前只支持internal的名惩,后續(xù)不排除放開這個限制。詳見開發(fā)者christen的討論[3]

Since all variables are pre-initialised in Solidity, so are return values of struct type (with their members being initialised recursively). This means if you use
function f() internal returns (Record r) { ... } you could also just assign the members of r individually.
The struct itself resides in memory and the function returns a reference to this point in memory. This means that in the case of "return records[recordID]", the storage-struct is first copied to memory and then the function returns a reference to this place in memory. If you would like to return the storage reference itself, you have to use "function ... returns (Record storage) { ... }".

3.1 繼承中使用

結(jié)構(gòu)體由于是不對外可見的孕荠,所以你只可以在當前合約娩鹉,或合約的子類中使用攻谁。包含自定義結(jié)構(gòu)體的函數(shù)均需要聲明為internal的。

pragma solidity ^0.4.0;

contract A{
  struct S{
    string para1;
    int para2;
  }

  function f(S s) internal{
      //...
  }

  function f1(){
    //當前類中使用結(jié)構(gòu)體
    S memory s = S("Test", 10);
    f(s);
  }
}

contract B is A{
  function g(){
      //字類中使用結(jié)構(gòu)體
      S memory s = S("Test", 10);

      //調(diào)用父類方法
      f(s);
  }
}

在上面的代碼中弯予,我們聲明了f(S s)戚宦,由于它包含了structS,所以不對外可見熙涤,需要標記為internal阁苞。你可以在當前類中使用它,如f1()所示祠挫,你還可以在子類中使用函數(shù)和結(jié)構(gòu)體,如B合約的g()方法所示悼沿。

4. 跨合約的臨時解決方案

結(jié)構(gòu)體等舔,由于是動態(tài)內(nèi)容。當前不支持在多個合約間互用糟趾,目前一種臨時的方案如下[4]:慌植。

pragma solidity ^0.4.0;

contract StructAcrossInitial{
  struct A{
    string para1;
    int para2;
  }

  function call(B b){
    A memory a = A("Test", 10);

    b.g(a.para1, a.para2);
  }
}

contract B{
  function g(string para1, int para2){
    //你要實現(xiàn)的內(nèi)容
  }
}

在上面的例子中,我們手動將要返回的結(jié)構(gòu)體拆解為基本類型進行了返回义郑。

關(guān)于作者

專注基于以太坊(Ethereum)的相關(guān)區(qū)塊鏈(Blockchain)技術(shù)蝶柿,了解以太坊,Solidity非驮,Truffle交汤,web3.js。

個人博客: http://me.tryblockchain.org
版權(quán)所有劫笙,轉(zhuǎn)載注明出處

參考資料


  1. http://ethereum.stackexchange.com/questions/15048/solidity-struct-initial-mapping-can-be-ignored ? ?

  2. http://ethereum.stackexchange.com/questions/13365/mapping-member-isnt-initialized-when-creating-a-struct/13367#13367 ?

  3. https://forum.ethereum.org/discussion/1994/does-solidity-allow-struct-return-types ?

  4. http://ethereum.stackexchange.com/questions/11016/copy-a-struct-from-contract-a-into-a-struct-in-contract-b-using-contract-c/11020#11020 ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芙扎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子填大,更是在濱河造成了極大的恐慌戒洼,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件允华,死亡現(xiàn)場離奇詭異圈浇,居然都是意外死亡,警方通過查閱死者的電腦和手機靴寂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門磷蜀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人榨汤,你說我怎么就攤上這事蠕搜。” “怎么了收壕?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵妓灌,是天一觀的道長轨蛤。 經(jīng)常有香客問我,道長虫埂,這世上最難降的妖魔是什么祥山? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮掉伏,結(jié)果婚禮上缝呕,老公的妹妹穿的比我還像新娘。我一直安慰自己斧散,他們只是感情好供常,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸡捐,像睡著了一般栈暇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上箍镜,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天源祈,我揣著相機與錄音,去河邊找鬼色迂。 笑死香缺,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的歇僧。 我是一名探鬼主播图张,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼馏慨!你這毒婦竟也來了埂淮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤写隶,失蹤者是張志新(化名)和其女友劉穎倔撞,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慕趴,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡痪蝇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冕房。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躏啰。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耙册,靈堂內(nèi)的尸體忽然破棺而出给僵,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布帝际,位于F島的核電站蔓同,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蹲诀。R本人自食惡果不足惜斑粱,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脯爪。 院中可真熱鬧则北,春花似錦、人聲如沸痕慢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掖举。三九已至惑艇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拇泛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工思灌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俺叭,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓泰偿,卻偏偏與公主長得像熄守,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耗跛,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容