【開發智能合約 — Solidity系列】實作篇Ep.6 -關於可視範圍(Visibility)

閱讀時間約 16 分鐘
為什麼要特別介紹可視範圍呢? 試想,假如我們的合約裡有些非常重要的內容只能侷限於合約內使用,此時就可以運用可視範圍的技巧,將某些重要的功能、狀態鎖定在合約內使用,不隨意開放給外部調用,避免汙染內部,但有些又是共用的內容及功能時,我們就可以利用公開的可視範圍讓相同的功能能夠重複使用。
合約中又可以依照不同的分責區分可視範圍,在Solidity的世界中主要會分為兩大類型的可視範圍,分別是狀態變數(State Variable)跟功能(Function)。

狀態變數(State Variable)的可視範圍

public

這種可視範圍最為寬鬆,除了內部合約以外,繼承與外部合約也都能夠進行調用。
contract Base {
// [Scope]
// - inside Base Contract
// - inside contracts that inherit this contract
// - by other contracts
string public publicMsg = "public state variables"; function testScope() public virtual {
// ✔️ 可以存取「Base」的public 變數
require(bytes(publicMsg).length > 0, "cannot access public state variable");
}} contract Extend is Base { function testScope() public view override {

// ✔️ 可以存取「Base」的public 變數
require(bytes(publicMsg).length > 0, "cannot access public state variable");
}
}contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base(); // ✔️ 可以存取「Base」的public變數
b.publicMsg;
}
}

internal

除了自身的合約以外,繼承的合約也能夠調用,但外部合約是不可視的。
contract Base {
// [Scope]
// - inside Base Contract
// - inside contracts that inherit this contract
string internal internalMsg = "internal state variables"; function testScope() public virtual {
// ✔️ 可以存取「Base」的internal 變數
require(bytes(internalMsg).length > 0, "cannot access internal state variable");
}} contract Extend is Base { function testScope() public view override {
// ✔️ 可以存取「Base」的internal 變數
require(bytes(internalMsg).length > 0, "cannot access internal state variable");
}
}contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base();

// ❌ 無法存取「Base」的internal變數
// @notice 語法檢測錯誤: not found or not visible after argument-dependent lookup in contract Base.
// b.internalMsg;
}
}

private

這種可視範圍僅侷限於自身的合約之中,不可被外部合約調用,包括繼承的合約也是不可視的。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7.0;contract Base {
// State variables
// [Scope]
// - inside Base Contract
string private privateMsg = "private state variables";
function testScope() public virtual {
// ✔️ 可以存取「Base」的private 變數
require(bytes(privateMsg).length > 0, "cannot access private state variable");
}} contract Extend is Base {
function testScope() public view override {
// ❌ 無法使用基礎合約的私有狀態變數
// @notice 語法檢測錯誤: DeclarationError: Undeclared identifier.
// require(bytes(privateMsg).length > 0, "cannot access private state variable");
}
}contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base(); // ❌ 無法存取「Base」的private變數
// @notice 語法檢測錯誤: not found or not visible after argument-dependent lookup in contract Base.
// b.privateMsg;
}
}

功能(Function)的可視範圍

Function的部分比較特殊,擴增了external,這也是我們在傳統的程式語言中比較少見的一種應用,以下就讓我們來好好介紹這個部分。

external

僅外部的合約可以進行調用,內部以及繼承的合約皆不可視,主要用意是當我們不確定這個功能是否內部也會調用時,可以宣告為external,一旦宣告為external之後,內部要調用就得使用this.xxx()才能調用,另外參數的部分是使用Calldata作為來源,會減少許多不必要的Copy。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7.0;contract Base {
// [Scope]
// - by other contracts
function externalJob() external pure returns (string memory) {
return "external job called";
} function testScope() public virtual {
// ❌ 僅能由外部合約進行呼叫
// @notice 語法檢測錯誤: DeclarationError: Undeclared identifier. Did you mean "internalJob" or "externalJob"?
// externalJob(); // ✔️ 但可以使用這種方式在內部進行調用
this.externalJob();
}} contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base();
b.externalJob();
}
}

public

可視範圍就如同狀態變數的public一樣,除了內部合約以外,繼承與外部合約也都能夠進行調用。
contract Base {
// [Scope]
// - inside this contract
// - inside contracts that inherit this contract
// - by other contracts
function publicJob() public pure returns (string memory) {
return "public job called";
} function testScope() public virtual {
// ✔️ 可以存取「Base」的public Function
publicJob();
}} contract Extend is Base { function testScope() public view override {
// ✔️ 可以存取「Base」的public Function
publicJob();
}
}contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base(); // ✔️ 可以存取「Base」的public Function
b.publicJob();
}
}

internal

可視範圍一樣同狀態變數的internal,除了自身的合約以外,繼承的合約也能夠調用,但外部合約是不可視的。
contract Base {
// [Scope]
// - inside this contract
// - inside contracts that inherit this contract
function internalJob() internal pure returns (string memory) {
return "internal job called";
} function testScope() public virtual {
// ✔️ 可以存取「Base」的internal Function
internalJob();
}} contract Extend is Base { function testScope() public view override {
// ✔️ 可以存取「Base」的internal Function
internalJob();
}
}contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base(); // ❌ 無法存取「Base」的internal Function
// @notice 語法檢測錯誤: not found or not visible after argument-dependent lookup in contract Base.
// b.internalJob();
}
}

private

這種可視範圍僅侷限於自身的合約之中,不可被外部合約調用,包括繼承的合約也是不可視的。
contract Base {
// [Scope]
// - inside Base Contract
function privateJob() private pure returns(string memory) {
return "private job called";
} function testScope() public virtual {
// ✔️ 可以存取「Base」的private Function
privateJob();
}} contract Extend is Base { function testScope() public view override {
// ❌ 無法使用基礎合約的私有成員Function
// @notice 語法檢測錯誤: DeclarationError: Undeclared identifier
// privateJob();
}
}contract External {
function testScope() public {
// 宣告Base合約並呼叫其開放外部的Job
Base b = new Base(); // ❌ 無法存取「Base」的private Function
// @notice 語法檢測錯誤: not found or not visible after argument-dependent lookup in contract Base.
// b.privateJob();
}

結語

以上是這次篇章介紹的可視範圍用法,撰寫一份安全的合約時,我們務必注意什麼能開放,開放到什麼程度,這些都與可視範圍息息相關,後續維護時也較能明確的界定範圍,不至於全部開放導致混亂,或者全部封閉導致一堆重複的內容。
今天的範例都在這裡「📦 solidity-remix-toturial/Ep6」歡迎自行取用。
為什麼會看到廣告
109會員
249Content count
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
發表第一個留言支持創作者!
阿Han的沙龍 的其他內容
Solidity語言的錯誤檢查提供了Require()、Revert()、Assert(),這三種方便的API調用,而這三種用途分別不同,畢竟牽涉到瓦斯費的問題,因此才會與過往的程式語言有些許的差異, require()通常會被使用在輸入值的驗證檢查,因為它的特性主要是能夠退回剩餘的Gas fee,
每個產品在實驗室研發出來後,勢必會面臨到賣給客戶的階段,那麼當我們將產品移交給客戶時,意味著也要進行環境的安裝,但問題來了,每一個客戶的環境差異甚大,總不可能為了A客戶就建立一個A客戶的環境,因應B客戶就建立B客戶的環境,這樣隨著產品的銷售量增長也將連帶耗盡公司的資源,想必這不是我們所樂見的現象,當
建議閱讀前可以先了解一下「【開發智能合約 — Solidity系列】開發環境準備」,會比較容易操作Remix來開發智能合約。 Remix IDE的Debug方式其實也類似於我們開發軟體程式過程中的Debug流程,編輯好程式碼之後,經過編譯,發佈到暫存鏈上,對每一個區塊進行Debug,過程中逐步排查出
「人」與「人」之間無非時時刻刻都在交易,只是每一種交易的形式與媒介有所不同,而區塊鏈的世界也有特定的交易單位,主要分為兩大類型的單位, 分別是以乙太幣單位以及時間單位。 最小單位為「wei」, 而其餘主要會用到的單位分別是「gwei」與「ether」。 時間單位的部份就比較容易理解了, 非常直觀,
資料型態在合約當中扮演著什麼角色呢? 我們在「【開發智能合約 — Solidity系列】實作篇Ep.2 — 合約中的基本組成元素」有介紹過狀態變數可以儲存一些變化值,而儲存什麼類型的值就是所謂的資料型態,不同的資料型態可以處理的事物也有所不同,因此我們也需要了解一些基本的資料型態以及特性之後,未來開
Solidity語言的錯誤檢查提供了Require()、Revert()、Assert(),這三種方便的API調用,而這三種用途分別不同,畢竟牽涉到瓦斯費的問題,因此才會與過往的程式語言有些許的差異, require()通常會被使用在輸入值的驗證檢查,因為它的特性主要是能夠退回剩餘的Gas fee,
每個產品在實驗室研發出來後,勢必會面臨到賣給客戶的階段,那麼當我們將產品移交給客戶時,意味著也要進行環境的安裝,但問題來了,每一個客戶的環境差異甚大,總不可能為了A客戶就建立一個A客戶的環境,因應B客戶就建立B客戶的環境,這樣隨著產品的銷售量增長也將連帶耗盡公司的資源,想必這不是我們所樂見的現象,當
建議閱讀前可以先了解一下「【開發智能合約 — Solidity系列】開發環境準備」,會比較容易操作Remix來開發智能合約。 Remix IDE的Debug方式其實也類似於我們開發軟體程式過程中的Debug流程,編輯好程式碼之後,經過編譯,發佈到暫存鏈上,對每一個區塊進行Debug,過程中逐步排查出
「人」與「人」之間無非時時刻刻都在交易,只是每一種交易的形式與媒介有所不同,而區塊鏈的世界也有特定的交易單位,主要分為兩大類型的單位, 分別是以乙太幣單位以及時間單位。 最小單位為「wei」, 而其餘主要會用到的單位分別是「gwei」與「ether」。 時間單位的部份就比較容易理解了, 非常直觀,
資料型態在合約當中扮演著什麼角色呢? 我們在「【開發智能合約 — Solidity系列】實作篇Ep.2 — 合約中的基本組成元素」有介紹過狀態變數可以儲存一些變化值,而儲存什麼類型的值就是所謂的資料型態,不同的資料型態可以處理的事物也有所不同,因此我們也需要了解一些基本的資料型態以及特性之後,未來開
你可能也想看
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
台股收在21858點,然後就端午節了。有好幾年都很怕端午變盤,沒想到做股票久了就也不怕了。 端午節前發現開發金有漲,查了一下,原來是改名+二王子要回來了,目前股價15元。
Thumbnail
親愛的讀者,你知道什麼是LOGO嗎? LOGO是:外來語到對標誌擁有公司的識別和推廣的作用,透過形象的logo可以讓消費者記住公司主體和品牌文化。 標誌特徵與特性: 延展性:企業logo是應用最為廣泛,出現頻率最高的視覺傳達要素,必須在各種傳播媒體上廣泛應用。logo圖形要針對印刷
Thumbnail
《經濟日報》日前於台北國際會議中心盛大舉辦「2023生技論壇」,邀請衛福部長薛瑞元、生策會副會長楊泮池、長佳智能董座陳明豐在內的多位官、商、學界專家、學者參與盛會,深入研討新冠肺炎疫情後的經濟重組;瞄準再生醫療、精準醫療、大健康領域等生技產業範疇,藉由共同發聲、齊心努力,對此應有推波助瀾之效。
Thumbnail
剛好前陣子在求職平台/人力銀行服務,一直在思考整個產品要如何進行迭代優化,以及要如何根據使用者需求來制定產品路線圖、開發優先順序,這篇會介紹求職平台的產品特點、使用者路徑、以及從產品優化的角度如何拆解。
Thumbnail
購買網站:https://shopee.tw/【樂意創客官方店】 使用方式 擴展網址:https://github.com/lzty634158/GHBit 在擴展頁面輸入“https://github.com/lzty634158/GHBit” 按下Enter 搜尋,就可以發現GHBit
Thumbnail
介紹了這麼多Solidity的函數和方法,今天來寫一個簡單的錢包,順便介紹一下payable。
此篇我們也來介紹另外一個也是蠻常用又蠻重要的Mapping,它和陣列有點像,但比較不同的是:它不能用迴圈的方式取出裡面所有的資料,但陣列可以,Mapping比較像是一個查詢系統,用key值可以取出裡面的value值。
Thumbnail
這篇我們來看一個在程式開發很常見也很常用的一個東西:Array 陣列 Array在所有的程式開發中還蠻常見的,也一定會出現,因為有很多的資料都會是一長串的,需要有一個物件來去做集中管理。
在寫程式裡面,錯誤的檢查和處理是一定要有的,也是相對重要的,但Solidity裡面並沒有ErrorMessage這種東西,有的是Require()、Revert()、Assert()這三個函數,作用大概也跟ErrorMessage差不多,這裡介紹這三種函數的用法
我們知道function除了四種可見度 (visibility) 之外,還有三種比較常見的函式修飾詞(view、pure、payable),這篇就也來認識一下這三種函式修飾詞是做什麼用的吧。
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
台股收在21858點,然後就端午節了。有好幾年都很怕端午變盤,沒想到做股票久了就也不怕了。 端午節前發現開發金有漲,查了一下,原來是改名+二王子要回來了,目前股價15元。
Thumbnail
親愛的讀者,你知道什麼是LOGO嗎? LOGO是:外來語到對標誌擁有公司的識別和推廣的作用,透過形象的logo可以讓消費者記住公司主體和品牌文化。 標誌特徵與特性: 延展性:企業logo是應用最為廣泛,出現頻率最高的視覺傳達要素,必須在各種傳播媒體上廣泛應用。logo圖形要針對印刷
Thumbnail
《經濟日報》日前於台北國際會議中心盛大舉辦「2023生技論壇」,邀請衛福部長薛瑞元、生策會副會長楊泮池、長佳智能董座陳明豐在內的多位官、商、學界專家、學者參與盛會,深入研討新冠肺炎疫情後的經濟重組;瞄準再生醫療、精準醫療、大健康領域等生技產業範疇,藉由共同發聲、齊心努力,對此應有推波助瀾之效。
Thumbnail
剛好前陣子在求職平台/人力銀行服務,一直在思考整個產品要如何進行迭代優化,以及要如何根據使用者需求來制定產品路線圖、開發優先順序,這篇會介紹求職平台的產品特點、使用者路徑、以及從產品優化的角度如何拆解。
Thumbnail
購買網站:https://shopee.tw/【樂意創客官方店】 使用方式 擴展網址:https://github.com/lzty634158/GHBit 在擴展頁面輸入“https://github.com/lzty634158/GHBit” 按下Enter 搜尋,就可以發現GHBit
Thumbnail
介紹了這麼多Solidity的函數和方法,今天來寫一個簡單的錢包,順便介紹一下payable。
此篇我們也來介紹另外一個也是蠻常用又蠻重要的Mapping,它和陣列有點像,但比較不同的是:它不能用迴圈的方式取出裡面所有的資料,但陣列可以,Mapping比較像是一個查詢系統,用key值可以取出裡面的value值。
Thumbnail
這篇我們來看一個在程式開發很常見也很常用的一個東西:Array 陣列 Array在所有的程式開發中還蠻常見的,也一定會出現,因為有很多的資料都會是一長串的,需要有一個物件來去做集中管理。
在寫程式裡面,錯誤的檢查和處理是一定要有的,也是相對重要的,但Solidity裡面並沒有ErrorMessage這種東西,有的是Require()、Revert()、Assert()這三個函數,作用大概也跟ErrorMessage差不多,這裡介紹這三種函數的用法
我們知道function除了四種可見度 (visibility) 之外,還有三種比較常見的函式修飾詞(view、pure、payable),這篇就也來認識一下這三種函式修飾詞是做什麼用的吧。