国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

玩以太坊鏈上項目的必備技能(類型-引用類型-Solidity之旅三)

這篇具有很好參考價值的文章主要介紹了玩以太坊鏈上項目的必備技能(類型-引用類型-Solidity之旅三)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

在前文我們講述了值類型,也就說再修改值類型的時候,每次都有一個獨立的副本,如:string 類型的狀態(tài)變量,其值是無法修改,而是拷貝出一份該狀態(tài)的變量,將新值存起來。對于處理稍微復雜地值類型時,拷貝將變得愈發(fā)大了,也正是介于此,才考慮到將數(shù)據(jù)存放在內(nèi)存(memory)或是存放在存儲(storage)。

在 Solidity 中,數(shù)組(array)和 結(jié)構(gòu)體(struct)屬于引用類型。

更改數(shù)據(jù)位置或類型轉(zhuǎn)換將始終產(chǎn)生自動進行一份拷貝,而在同一數(shù)據(jù)位置內(nèi)(對于 存儲(storage) 來說)的復制僅在某些情況下進行拷貝。

數(shù)據(jù)位置和賦值行為

所有的引用類型,如數(shù)組(array0結(jié)構(gòu)體(struct)類型,都有別同于其他類型,那便是引用類型有額外地屬性——數(shù)據(jù)位置。

數(shù)據(jù)位置,顧名思義就是數(shù)據(jù)存放的位置在哪里?是在內(nèi)存(memory)中還是在存儲(storage)中。

當然咯,大多時候數(shù)據(jù)都有默認的存放位置。也可顯式地修改其數(shù)據(jù)存放的位置,只需在類型后添加memorystorage。

函數(shù)參數(shù)/形參(包括函數(shù)的返回參數(shù))數(shù)據(jù)位置默認在memory,局部變量數(shù)據(jù)位置則默認在storage,但狀態(tài)變量數(shù)據(jù)位置被強制在storage。

還有一個調(diào)用數(shù)據(jù)(calldata)存儲方式,用于存放外部函數(shù)(external)的參數(shù)/形參,其效果跟memory差不離。

指定數(shù)據(jù)存放的位置是非常的重要,因為它們將會影響其賦值行為。

  • 在 存儲storage 和 內(nèi)存memory 之間兩兩賦值(或者從 調(diào)用數(shù)據(jù)calldata 賦值 ),都會創(chuàng)建一份獨立的拷貝。
  • 從 內(nèi)存memory 到 內(nèi)存memory 的賦值只創(chuàng)建引用, 這意味著更改內(nèi)存變量,其他引用相同數(shù)據(jù)的所有其他內(nèi)存變量的值也會跟著改變。
  • 從 存儲storage 到本地存儲變量的賦值也只分配一個引用。
  • 其他的向 存儲storage 的賦值,總是進行拷貝。 這種情況的示例如對狀態(tài)變量或 存儲storage 的結(jié)構(gòu)體類型的局部變量成員的賦值,即使局部變量本身是一個引用,也會進行一份拷貝(譯者注:查看下面 ArrayContract 合約 更容易理解)。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.0;

contract StorageExam {
    uint[] x; // x 的數(shù)據(jù)存儲位置是 storage

    // memoryArray 的數(shù)據(jù)存儲位置是 memory
    function f(uint[] memory memoryArray) public {
        x = memoryArray; // 將整個數(shù)組拷貝到 storage 中
        uint[] storage y = x;  // 分配一個指針(其中 y 的數(shù)據(jù)存儲位置是 storage)
        y[7]; // 返回第 8 個元素
        y.pop(); // 通過 y 修改 x
        delete x; // 刪除數(shù)組 x,同樣也會刪除數(shù)組 y

        // 下面的方法不起作用;它需要在存儲中創(chuàng)建一個新的臨時未命名數(shù)組
        // 未命名的數(shù)組,但存儲是 "靜態(tài) "分配的。
        // y = memoryArray;
        // 同樣,"刪除y "也是無效的,因為對本地變量的賦值只能從現(xiàn)有的存儲對象中進行。
        // 它將 "重置 "指針,但是沒有任何合理的位置可以讓它指向
        // delete y;

        g(x); // 調(diào)用 g 函數(shù),同時移交對 x 的引用
        h(x); // 調(diào)用 h 函數(shù),同時在 memory 中創(chuàng)建一個獨立的臨時副本
    }

    function g(uint[] storage ) internal pure {}
    function h(uint[] memory) public pure {}
}

歸納為:

強制指定的數(shù)據(jù)位置:

  • 外部函數(shù)的參數(shù)(不包括返回參數(shù)): calldata
  • 狀態(tài)變量: storage

默認數(shù)據(jù)位置:

  • 函數(shù)參數(shù)(包括返回參數(shù)): memory
  • 所有其它局部變量: storage

數(shù)組(array)

數(shù)組是用來存放一組數(shù)據(jù)(整數(shù)、字符串、地址等),它是一種常見的數(shù)據(jù)類型,而在 Solidity 中,數(shù)組可分為編譯時的固定大小,動態(tài)大小的兩種數(shù)組。

固定大小數(shù)組聲明格式:

T[k] // T 為元素類型  k則是數(shù)組的大小
uint[7] arr;
address[50] address1;

動態(tài)大小數(shù)組聲明格式:

T[] //T為元素類型  由于是動態(tài)分配的 所以只需[]
unit[] arr2;
bytes1[] arr3;
address[] arr4;
bytes arr5;  //注意 bytes本身就是數(shù)組

一個長度為 5,元素類型為 uint 的動態(tài)數(shù)組的數(shù)組(二維數(shù)組),應聲明為 uint[][5] (注意這里跟其它語言比,數(shù)組長度的聲明位置是反的)。作為對比,如在Java中,聲明一個包含5個元素、每個元素都是數(shù)組的方式為 int[5][]

在Solidity中, X[3] 總是一個包含三個 X 類型元素的數(shù)組,即使 X 本身就是一個數(shù)組,這和其他語言也有所不同,比如 C 語言。

數(shù)組下標是從 0 開始的,且訪問數(shù)組時的下標順序與聲明時相反。

如果有一個變量為 uint[][5] memory x, 要訪問第三個動態(tài)數(shù)組的第7個元素,使用 x[2][6],要訪問第三個動態(tài)數(shù)組使用 x[2]。 同樣,如果有一個 T 類型的數(shù)組 T[5] a , T 也可以是一個數(shù)組,那么 a[2] 總會是 T 類型。

數(shù)組元素可以是任何類型,包括映射或結(jié)構(gòu)體。對類型的限制是映射只能存儲在 存儲storage 中,并且公開訪問函數(shù)的參數(shù)需要是 ABI 類型。

狀態(tài)變量標記 public 的數(shù)組,Solidity創(chuàng)建一個 getter函數(shù) 。 小標數(shù)字索引就是 getter函數(shù) 的參數(shù)。

訪問超出數(shù)組長度的元素會導致異常(assert 類型異常 )。 可以使用 .push() 方法在末尾追加一個新元素,其中 .push() 追加一個零初始化的元素并返回對它的引用。

bytesstring 類型的變量是特殊的數(shù)組。 bytes 類似于 bytes1[],但它在 調(diào)用數(shù)據(jù)calldata 和 內(nèi)存memory 中會被“緊打包”(譯者注:將元素連續(xù)地存在一起,不會按每 32 字節(jié)一單元的方式來存放)。 stringbytes 相同,但不允許用長度或索引來訪問。

Solidity沒有字符串操作函數(shù),但是可以使用第三方字符串庫,我們可以比較兩個字符串通過計算他們的 keccak256-hash ,可使用 keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)) 和使用 string.concat(s1, s2) 來拼接字符串。

我們更多時候應該使用 bytes 而不是 bytes1[] ,因為Gas 費用更低, 在 內(nèi)存memory 中使用 bytes1[] 時,會在元素之間添加31個填充字節(jié)。 而在 存儲storage 中,由于緊密包裝,這沒有填充字節(jié)。 作為一個基本規(guī)則,對任意長度的原始字節(jié)數(shù)據(jù)使用 bytes,對任意長度字符串(UTF-8)數(shù)據(jù)使用 string 。

可以將數(shù)組標識為 public,從而讓 Solidity 創(chuàng)建一個 getter。 之后必須使用數(shù)字下標作為參數(shù)來訪問 getter。

創(chuàng)建數(shù)組規(guī)則
  • 使用new在內(nèi)存(memory)中創(chuàng)建動態(tài)數(shù)組,需聲明長度,且在聲明后不能修改數(shù)組的大小
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.16;

contract Arr {
    function f(uint len) public pure {
        uint[] memory a = new uint[](7);
        bytes memory b = new bytes(len);
        // 這里我們有 a.length == 7 以及 b.length == len
        a[6] = 8;
    }
}
  • 數(shù)組字面常數(shù)是一種定長的 內(nèi)存(memory) 數(shù)組類型,它的基礎(chǔ)類型是由其中元素的類型決定。 例如,[1, 2, 3] 的類型是 uint8[3] memory,因為其中的每個字面常數(shù)的類型都是 uint8。 正因為如此,有必要將上面這個例子中的第一個元素轉(zhuǎn)換成 uint 類型。 目前需要注意的是,定長的 內(nèi)存memory 數(shù)組并不能賦值給變長的 內(nèi)存memory 數(shù)組
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.16;

contract C {
    function f() public pure {
        g([uint(1), 2, 3]);
    }
    function g(uint[3] _data) public pure {
        // ...
    }
}
// SPDX-License-Identifier: GPL-3.0
// 這段代碼并不能編譯。
pragma solidity ^0.4.0;

contract C {
    function f() public {
        // 這一行引發(fā)了一個類型錯誤,因為 unint[3] memory
        // 不能轉(zhuǎn)換成 uint[] memory。
        uint[] x = [uint(1), 3, 4];
    }
}
數(shù)組成員
  • length: 數(shù)組有一個包含元素數(shù)量的length成員,memory數(shù)組的長度在創(chuàng)建后是固定的。
  • push(): 動態(tài)數(shù)組bytes擁有push()成員,可以在數(shù)組最后添加一個0元素。
  • push(x): 動態(tài)數(shù)組bytes擁有push(x)成員,可以在數(shù)組最后添加一個x元素。
  • pop(): 動態(tài)數(shù)組bytes擁有pop()成員,可以移除數(shù)組最后一個元素。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.16;

contract ArrayContract {
    uint[2**20] m_aLotOfIntegers;
    // 注意下面的代碼并不是一對動態(tài)數(shù)組,
    // 而是一個數(shù)組元素為一對變量的動態(tài)數(shù)組(也就是數(shù)組元素為長度為 2 的定長數(shù)組的動態(tài)數(shù)組)。
    bool[2][] m_pairsOfFlags;
    // newPairs 存儲在 memory 中 —— 函數(shù)參數(shù)默認的存儲位置

    function setAllFlagPairs(bool[2][] newPairs) public {
        // 向一個 storage 的數(shù)組賦值會替代整個數(shù)組
        m_pairsOfFlags = newPairs;
    }

    function setFlagPair(uint index, bool flagA, bool flagB) public {
        // 訪問一個不存在的數(shù)組下標會引發(fā)一個異常
        m_pairsOfFlags[index][0] = flagA;
        m_pairsOfFlags[index][1] = flagB;
    }

    function changeFlagArraySize(uint newSize) public {
        // 如果 newSize 更小,那么超出的元素會被清除
        m_pairsOfFlags.length = newSize;
    }

    function clear() public {
        // 這些代碼會將數(shù)組全部清空
        delete m_pairsOfFlags;
        delete m_aLotOfIntegers;
        // 這里也是實現(xiàn)同樣的功能
        m_pairsOfFlags.length = 0;
    }

    bytes m_byteData;

    function byteArrays(bytes data) public {
        // 字節(jié)的數(shù)組(語言意義中的 byte 的復數(shù) ``bytes``)不一樣,因為它們不是填充式存儲的,
        // 但可以當作和 "uint8[]" 一樣對待
        m_byteData = data;
        m_byteData.length += 7;
        m_byteData[3] = byte(8);
        delete m_byteData[2];
    }

    function addFlag(bool[2] flag) public returns (uint) {
        return m_pairsOfFlags.push(flag);
    }

    function createMemoryArray(uint size) public pure returns (bytes) {
        // 使用 `new` 創(chuàng)建動態(tài) memory 數(shù)組:
        uint[2][] memory arrayOfPairs = new uint[2][](size);
        // 創(chuàng)建一個動態(tài)字節(jié)數(shù)組:
        bytes memory b = new bytes(200);
        for (uint i = 0; i < b.length; i++)
            b[i] = byte(i);
        return b;
    }
}

結(jié)構(gòu)體(struct)

Solidity 中的結(jié)構(gòu)體與 c 語言、golang 很相似,通過構(gòu)造結(jié)構(gòu)體來定義一種新類型。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.11;

contract CrowdFunding {
    // 定義的新類型包含兩個屬性。
    struct Funder {
        address addr;
        uint amount;
    }

    struct Campaign {
        address beneficiary;
        uint fundingGoal;
        uint numFunders;
        uint amount;
        mapping (uint => Funder) funders; //這是 映射  后續(xù)會講到
    }

    uint numCampaigns;
    mapping (uint => Campaign) campaigns; //這是 映射  后續(xù)會講到

    function newCampaign(address beneficiary, uint goal) public returns (uint campaignID) {
        campaignID = numCampaigns++; // campaignID 作為一個變量返回
        // 創(chuàng)建新的結(jié)構(gòu)體示例,存儲在 storage 中。我們先不關(guān)注映射類型。
        campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
    }

    function contribute(uint campaignID) public payable {
        Campaign storage c = campaigns[campaignID];
        // 以給定的值初始化,創(chuàng)建一個新的臨時 memory 結(jié)構(gòu)體,
        // 并將其拷貝到 storage 中。
        // 注意你也可以使用 Funder(msg.sender, msg.value) 來初始化。
        c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value});
        c.amount += msg.value;
    }

    function checkGoalReached(uint campaignID) public returns (bool reached) {
        Campaign storage c = campaigns[campaignID];
        if (c.amount < c.fundingGoal)
            return false;
        uint amount = c.amount;
        c.amount = 0;
        c.beneficiary.transfer(amount);
        return true;
    }
}

上面的合約只是一個簡化版的眾籌合約,但它已經(jīng)足以讓我們理解結(jié)構(gòu)體的基礎(chǔ)概念。 結(jié)構(gòu)體類型可以作為元素用在映射和數(shù)組中,其自身也可以包含映射和數(shù)組作為成員變量。

盡管結(jié)構(gòu)體本身可以作為映射的值類型成員,但它并不能包含自身。 這個限制是有必要的,因為結(jié)構(gòu)體的大小必須是有限的。

注意在函數(shù)中使用結(jié)構(gòu)體時,一個結(jié)構(gòu)體是如何賦值給一個局部變量(默認存儲位置是 存儲(storage) )的。 在這個過程中并沒有拷貝這個結(jié)構(gòu)體,而是保存一個引用,所以對局部變量成員的賦值實際上會被寫入狀態(tài)。

當然,你也可以直接訪問結(jié)構(gòu)體的成員而不用將其賦值給一個局部變量,就像這樣, campaigns[campaignID].amount = 0

http:// spdx-license-identifier: gpl-3.0 pragma solidity 0.4.24; contract lenet5,區(qū)塊鏈,區(qū)塊鏈,solidity,結(jié)構(gòu)體,引用類型,值拷貝文章來源地址http://www.zghlxwxcb.cn/news/detail-821589.html

到了這里,關(guān)于玩以太坊鏈上項目的必備技能(類型-引用類型-Solidity之旅三)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 以太坊智能合約開發(fā):Solidity 語言中的數(shù)據(jù)類型

    以太坊智能合約開發(fā):Solidity 語言中的數(shù)據(jù)類型

    本文我們介紹Solidity語言的數(shù)據(jù)類型,重點是值類型,包括布爾類型、整型、地址類型、字節(jié)類型、字符串類型和枚舉類型。并且通過兩個智能合約例子,用于演示這些數(shù)據(jù)類型的聲明與使用方法。 訪問 Github 倉庫 獲取更多資料。 Solidity中關(guān)于數(shù)據(jù)類型的定義如下: Solidity是

    2024年02月02日
    瀏覽(31)
  • 【項目管理】AI時代項目經(jīng)理必備技能

    【項目管理】AI時代項目經(jīng)理必備技能

    ??博__主??:米碼收割機 ??技__能??:C++/Python語言 ??公眾號??:測試開發(fā)自動化【獲取源碼+商業(yè)合作】 ??榮__譽??:阿里云博客專家博主、51CTO技術(shù)博主 ??專__注??:專注主流機器人、人工智能等相關(guān)領(lǐng)域的開發(fā)、測試技術(shù)。 項目經(jīng)理在AI時代仍然是非常關(guān)鍵的角色

    2024年02月08日
    瀏覽(18)
  • 在本地以太坊私鏈上,使用go調(diào)用智能合約,獲取事件日志
  • 誰在以太坊區(qū)塊鏈上循環(huán)交易?TuGraph+Kafka的0元流圖解決方案

    都在說數(shù)據(jù)已經(jīng)成為新時代的生產(chǎn)資料。 但隨著大數(shù)據(jù)和人工智能等技術(shù)的發(fā)展,即便人們都知道數(shù)據(jù)的價值日益凸顯,卻無法憑借一己之力獲取和分析如此大規(guī)模的數(shù)據(jù)。 要想富,先修路。要想利用新時代的數(shù)據(jù)致富,也必須要有趁手的工具。只有合適的工具才能完成大

    2024年02月11日
    瀏覽(24)
  • 以太坊智能合約語言Solidity - 3 數(shù)組

    1字節(jié)(Byte) = 8位 (bit), bytes32 = 256位,bytes1 實質(zhì)上就等于 int8 固定長度的數(shù)組一旦被定義就無法再更改,并且長度在一開始就會被顯式定義 我們再來創(chuàng)建一個新的文件用來編寫代碼 字節(jié)數(shù)組無法進行基本運算,但是可以比較 字節(jié)數(shù)組還支持其他一些邏輯運算,具體計算結(jié)果

    2023年04月08日
    瀏覽(25)
  • 以太坊智能合約開發(fā):Solidity 語言快速入門

    以太坊智能合約開發(fā):Solidity 語言快速入門

    在本文中,我們從一個簡單的智能合約樣例出發(fā),通過對智能合約源文件結(jié)構(gòu)的剖析與介紹,使大家對Solidity語言有一個初步的認識。最后,我們將該智能合約樣例在 Remix 合約編譯器中編譯、部署,觀察其執(zhí)行結(jié)果。 在開始之前,我們先對Solidity有個初步的了解,即Solidity是

    2023年04月09日
    瀏覽(32)
  • 第四章 以太坊智能合約solidity介紹

    Solidity 是一門面向合約的、為實現(xiàn)智能合約而創(chuàng)建的高級編程語言,設(shè)計的目的是能在以太坊虛擬機上運行。 本章大概介紹合約的基本信息,合約的組成,語法方面不做過多的介紹,個人建議多閱讀官方文檔效果更佳,后續(xù)的章節(jié)會開發(fā)ERC20代幣合約案例以便于更好的學習智

    2024年02月06日
    瀏覽(26)
  • 自定義的搭建solidity開發(fā)環(huán)境(以太坊)

    環(huán)境地址 ? ?github:?GitHub - yinzhiqing/templete-sol: solidity platform(hardhat) ? ?gitlab:?zqy / templete-sol · GitLab 本項目利用openzapplin solc web3js hardhat nodejs 在ubuntu下搭建solidity合約開發(fā)環(huán)境.大多數(shù)功能實現(xiàn)了自動化(腳本)執(zhí)行. 特點: 1.開發(fā)環(huán)境可充分使用 2.合約可升級 3.記

    2024年02月01日
    瀏覽(27)
  • 以太坊智能合約開發(fā):Solidity語言中的映射

    以太坊智能合約開發(fā):Solidity語言中的映射

    本文我們介紹Solidity語言中的映射,包括映射的基本定義、語法、映射的變量聲明和基本讀寫操作。并且通過兩個智能合約例子演示了映射的定義與基本操作。 Solidity中關(guān)于映射的一些定義: 映射以鍵-值對(key = value)的形式存儲數(shù)據(jù); 鍵可以是任何內(nèi)置數(shù)據(jù)類型,包括字節(jié)

    2024年02月05日
    瀏覽(32)
  • 基于以太坊的智能合約開發(fā)Solidity(基礎(chǔ)篇)

    基于以太坊的智能合約開發(fā)Solidity(基礎(chǔ)篇)

    參考教程:基于以太坊的智能合約開發(fā)教程【Solidity】_嗶哩嗶哩_bilibili (1)程序編譯完成后,需要在虛擬機上運行,將合約部署好后便可執(zhí)行剛剛編寫的函數(shù)。(注意, 合約一旦部署,就會永久存在于區(qū)塊鏈上,且不可篡改 ,不過可以銷毀) (2)執(zhí)行完成后,可以得到以

    2024年02月04日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包