Synopsis
- 透過 struct 方式,容易看懂程式
- 透過 pointer 方式,降低 memory 的使用 (雖然在程式結束後,會自動回收用不到的 memory)
- 使用 func as method 方式,讓程式碼在 func 使用上更容易被理解
Example
一般來說,如果要用程式碼計算『圓形面積』、『長方形面積』,可以用一些簡單的方式攥寫
但回頭看這個程式碼,會發現
- 如果要追蹤『rx1, ry1, rx2, ry2』或者『cx, cy, cr』當程式碼一長 or 複雜,就很難理解這個參數的意義
- 儘管有寫註解,在 function 中,一樣很難快速理解
解決方案 : 使用 struct 來幫助理解
use struct
struct
是一種 type
, 它包含了名稱的欄位, 例如:可以把 Rectangle 寫成如下方式
1 |
|
- 新增一個 Coordinate 的物件, 類型(type)是 struct, 裡面夾帶 (x,y) 欄位
- 新增一個 Rectangle, 類型(type)是 struct 的物件, 裡面夾帶 ‘起始座標’ 與 ‘結束座標’
宣告方法可以有以下幾種
- 以下都相同,跟 (2) 不同的是,返回是一個指標
r := new(Rectangle)
, 而 new 的主要作用是為 type 申請 memory,並返回指向 memory 的指標
。r := &Rectangle{}
- 以下也都相同
var r Rectangle
r := Rectangle{}
r := Rectangle{Coordinate{}, Coordinate{}}
r := Rectangle{ start: Coordinate{}, end: Coordinate{},}
優化開始
- steps
- 將 func() 參數物件改為傳遞 struct
- 將 func() 中 strct 設定為指標
- function as a method
1. 將 func() 參數物件改為傳遞 struct
從上面的基本操作,建立了 Rectangle 物件, type 是 struct 所以將 rectangleArea() 與 distance() 變更為
1 |
|
在 main 中, 可以改為, 如此可以輕鬆地理解 r 來自於 Rectangle 這個結構中的欄位
1 |
|
2. 將 func() 中 strct 設定為指標
以上 func 中, 重新宣告了一個 Rectangle 的物件
可以使用 fmt.Printf("%p\n", ThePointer)
查看記憶體位置的變化
for example
0xc00009c000 <= main 中的 Rectangle 0xc00009c020 <= func 中的 Rectangle
但可以用 pointer, 避免重複宣告並佔用 memory, 浪費資源
1 |
|
在 main 中
1 |
|
3. function as a method
解決了以上的問題,會發現
- rectangle 與 circle 都有 area, 雖然可以在命名上作區別, 但有更好的方法
且可以透過
.
的方式, 快速地在編輯器上引用此 method - 在 main 中,帶入的物件是
&r
會有點難以理解
將 rectangleArea() 改為 rectangle 的 method
1 |
|
在 main 中
1 |
|
優化結束
這是一個簡短的例子,當我們將功能越寫越多時,程式碼會越複雜 我們可以透過此方法達成以下三個目的
- 透過 struct 方式,容易看懂程式
- 透過 pointer 方式,降低 memory 的使用 (雖然在程式結束後,會自動回收用不到的 memory)
- 使用 func as method 方式,讓程式碼在 func 使用上更容易被理解
結論
- 過於複雜的參數傳遞,雖然我們可以用命名方式來釐清,但名稱越長,也會使程式碼難以理解
- 優化並非將程式碼縮短(但的確在大型架構下,可以縮短,並更容易理解)
問題
一個人裡有各種資訊物件,身分證、健保卡、護照,都用在不同的地方,也都有各自的 ID 可以透過 struct 將 『身分證、健保卡、護照』 各自建立起來,用在不同的目的上 但是否有方法整合這些物件?
參考下篇: struct優化(二):interface