今天我們要回來重新檢視一下 golang 的各種 Scope(作用域),在開始 scope 的說明前還必須提到 golang 程式在 runtime 初始化的順序,確保我們對運行時每一個階段的掌握。
當我們開始執行 golang 的程序時,首先會將 import packages 內部的常數變數與 init() 完成後,才開始當前 main package 下的常數變數與 init(),最後執行 main()。此外需注意的是每個 package 內的 init() 都只會被執行一次,如同其保留的命名為“初始化”時使用。
請下載執行 basicGo/init/main.go 觀察其執行順序,觀察結果應如下。
> go run basicGo/init/main.go
package init() started
packageConst packageConst
packageVar packageVar
main init() started
mainConst mainConst
mainVar mainVar
main func started
hello
hello2
Scope(作用域) 的了解除了最基本的程式是否能正常運行外,也關乎你的變數是否容易被污染,若能仔細控制每一個變數的作用範圍的話,將能將有效提升服務的可靠度。
我們直接使用範例程式碼說明,如果是使用 VScode 當作編輯器的話可以看到很清楚的提示。當我們的主程式 import scpackage 使用的時候,能使用的方法只有大寫的 scpackage.Create(),能使用的 struct 只有 scpackage.Clinet。
Golang 編譯上會將
package scpackage
//Clinet example of scope
type Clinet struct {
IP string
Host string
setting detail
}
//小寫private,無法被其他 package 直接存取
type detail struct {
maxClient int
maxIdle int
}
//Create example of scope
func Create(ip, host string) *Clinet {
return &Clinet{
IP: ip,
Host: host,
setting: newSetting(),
}
}
//小寫private,無法被其他 package 直接存取
func newSetting() detail {
return detail{
maxClient: 100,
maxIdle: 10,
}
}
可直接使用的只有大寫Public
得到的 struct 內的 field 也是僅能直接操作 大寫Public 的部分
關於 block scope (區域作用域),我們可以簡單地用 "{ }" 範圍來觀察變數作用域影響,但實務上我們避免在 block 內以相同名稱命名變數。範例中 if{ } 內重新 var new 同樣名稱的變數,僅為方便讓我們了解 scope 的效果。
package main
import (
"fmt"
"ithome12/basicGo/scpackage"
)
var global = "a global var"
func main() {
//scope of package
client := scpackage.Create("127.0.0.1", "localhost")
fmt.Printf("%+v\n", client)
//scope of block
myFuncA()
myFuncB()
fmt.Println(global)
new := "new"
for i := 0; i < 1; i++ {
//new 被宣告於迴圈{}外,符合作用域可使用
//i 屬於此迴圈內宣告變數,故僅能作用於迴圈內
//newInFor 同 i,屬於此迴圈內宣告變數,故僅能作用於迴圈內
newInFor := "hi"
fmt.Println(i, new, newInFor)
}
//每個block{}都分別為新的作用域
//if 判斷式內的 "new" 變數與 先前的 "new" 變數,為不同實體,並有著不同記憶體位址
if len(new) > 0 {
new := "xxx"
fmt.Println(new, &new)
}
fmt.Println(new, &new)
}
func myFuncA() {
fmt.Println(global)
global = "changed by myFuncA"
}
func myFuncB() {
fmt.Println(global)
global = "changed by myFuncB"
}
result output
&{IP:127.0.0.1 Host:localhost setting:{maxClient:100 maxIdle:10}}
a global var
changed by myFuncA
changed by myFuncB
0 new hi
xxx 0xc000010280
new 0xc000010250