iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 9
0
Blockchain

區塊練起來-智能合約與DApp開發系列 第 9

[區塊練起來-智能合約與DApp開發] DAY 09 - Solidity 作用域與合約的繼承

貼心小語

上一篇提到了函式的控制結構以及錯誤處理的方式,對函式已經有了基本的了解,這一篇將會探討如何實作合約的繼承/images/emoticon/emoticon12.gif


函式的作用域

在實作合約的繼承前,需要先了解函式的作用域。在 Solidity 中,函式有四種作用域,分別是 publicprivateinternalexternal

Public

這是最常見的作用域,也是預設的作用域,所有成員都可以呼叫。

Private

這也是常見的作用域,可以給當前合約內部使用,無法直接由外部呼叫,也無法給繼承的合約使用。

Internal

這與多數物件導向語言的 protected 相似,可以在合約內部使用,包含了繼承的合約,但無法由外部呼叫。

External

這是比較特別的作用域,只能夠給外部使用,適合用來處理資料,並要在參數帶上 calldata 。由於只開放給外部使用,比起同時要開放給內部使用的 public 還要省 Gas。
基本上,我認為 externalpublic static 的變形,就是用來呼叫的運算邏輯。

function test(uint[] calldata array) external pure returns (uint[] memory) {
  return array;
}

合約的繼承

與多數的物件導向語言繼承概念差不多,不過不是使用 extends 而是 is 。也許會有人提問:這樣在部署的時候會產生幾個合約?(沒錯,又是剛開始學 Solidity 時的我)這個問題的答案就是 一個 ,因為 Solidity 會將繼承的合約程式碼複製到自身,所以不必擔心產生多個合約造成管理上的困難,那這邊我們就寫兩個合約來實作,分別是 商店員工

範例-商店合約

商店合約裡面設定 struct 來定義我們商品的庫存類別,並在創建時個設定為100,並提供 raise 函式增加商品存貨,以及 reduce 函式減少商品庫存。

pragma solidity ^0.5.0;

contract Store {

    struct goodsCount {
        uint candy;
        uint cookie;
        uint bread;
    }

    goodsCount internal stock;

    constructor() public {
        stock = goodsCount({
            candy: 100,
            cookie: 100,
            bread: 100
        });
    }

    function reduce(string memory name, uint quantity) internal {
        bytes32 inputName = keccak256(bytes(name));
        bytes32[3] memory goodsList = [keccak256(bytes("candy")), keccak256(bytes("cookies")), keccak256(bytes("bread"))];
        if (inputName == goodsList[0] && stock.candy >= quantity) {
            stock.candy -= quantity;
        } else if(inputName == goodsList[1] && stock.cookie >= quantity) {
            stock.cookie -= quantity;
        } else if(inputName == goodsList[2] && stock.bread >= quantity) {
            stock.bread -= quantity;
        } else {
            revert("Stock is undefined or is not enough.");
        }
    }

    function raise(string memory name, uint quantity) internal {
        bytes32 inputName = keccak256(bytes(name));
        bytes32[3] memory goodsList = [keccak256(bytes("candy")), keccak256(bytes("cookies")), keccak256(bytes("bread"))];
        if (inputName == goodsList[0]) {
            stock.candy += quantity;
        } else if(inputName == goodsList[1]) {
            stock.cookie += quantity;
        } else if(inputName == goodsList[2]) {
            stock.bread += quantity;
        }
    }
}

由於 Solidity 無法直接進行字串比對,所以運用 keccak256(bytes32 memory) 來進行

範例-員工合約

先使用 import 將商店合約引入,並用 is 來繼承。員工合約提供 sell 函式來販售商品,以 purchase 函式來進貨商品,以及使用 showStocks 來顯示存貨狀況。

pragma solidity ^0.5.0;

import "./Store.sol";

contract Staff is Store {

    function sell(string memory name, uint quantity) public {
        reduce(name, quantity);
    }

    function purchase(string memory name, uint quantity) public {
        raise(name, quantity);
    }

    function showStocks() external view returns (uint, uint, uint) {
        return (stock.candy, stock.cookie, stock.bread);
    }
}

今日小結

了解函式的作用域,並學習合約的繼承,將作用域運用在合約實作當中!另外字串比對的部分可以參考下方的資料,有許多種字串比對的方式,各有優缺點,各位開發者自行斟酌呦!


參考資料

Solidity 兩個 string 的比較


上一篇
[區塊練起來-智能合約與DApp開發] DAY 08 - Solidity 控制結構與函式
下一篇
[區塊練起來-智能合約與DApp開發] DAY 10 - Solidity的event log
系列文
區塊練起來-智能合約與DApp開發31

尚未有邦友留言

立即登入留言