這邊的無言,不是說Go的用法令人無言啦雖然有時候還真的有點無言,例如各種if err != nil
的時候
...
除了人們會用...
來代表我很無言之外,
在程式中也常會看到Golang很無言的...
常見的俗名或稱呼方式為:
...
共有四種用法:在之前 Day09 宣告Array的時候,我們也用過省略符號來省略長度。
省略長度是要編譯器幫我們計算Array陣列長度、自動將長度填入
而不是沒有長度的Slice。
https://play.golang.org/p/3G9tKGdOy1o
func main() {
var a = [...]int{1, 2, 3, 7, 8, 9}
fmt.Println(len(a))
fmt.Println(a)
}
/*
6
[1 2 3 7 8 9]
*/
那麼這個刪節點、省略符號
用在函式中,就稱作 可變函式(參數長度可變) Variadic Functions
意思即為,可以傳入多個參數(0~N個),不傳入也行。
長度未知、在不知道參數到底有幾個的時候,我們可以透過這個方法來解決,但需為同樣型別。其實...
就有點像[] Slice
的意思。
...
在一個func參數中只能出現一次,而且是放在最後的參數位置上
func test1(...int) {
}
// 省略符號只能放在最後的位置上
func test2(int, ...string) {
}
// 這個會報錯 Can only use '...' as final argument in list
func test3(... int, ... string) {
}
先滿足必要的參數,再來填入剩下的剩餘參數
換角度思考一下,如果一開始在第一個元素上放省略符號
我大Golang編譯器要怎麼知道此人到底想省略幾個元素?
https://play.golang.org/p/KqmPFdQXTHV
func main() {
s1 := sum()
fmt.Println(s1)
s2 := sum(1, 5, 9)
fmt.Println(s2)
}
func sum(nums ...int) int {
var total int
for _, num := range nums {
total += num
}
return total
}
/*
0
15
*/
在這個地方,省略長度的int nums
,像極了Slice
根本就是Slice
在不同的地方上面可以代表不同的意涵,
省略符號 ...
也可以使用在很暴力殘忍的地方上,例如 將Slice 剝皮
。
水能載舟亦能覆舟,才剛把他弄成Slice,現在又要將他剝皮。
func sumUnpacking(nums ...int) int { // 傳入int但不曉得參數長度為何
var total int
for _, num := range nums {
total += num
}
return total
}
func main() {
slice := []int{2, 3, 5}
sum1 := sumUnpacking(slice...) // 把slice 解開、剝皮後傳入,同下
fmt.Println(sum1)
}
/* result:
10
*/
那到底什麼時候是
Slice
、什麼時候是省略長度
、什麼時候會被剝皮
?
以下整理了三種不同的方式來比較、探討Slice與
功能皆為實現一群數字的加總
https://play.golang.org/p/PKdWcjr_RUe
func main() {
slice := []int{2, 3, 5}
sum1 := sumUnpacking(slice...) // 把slice 解開、剝皮後傳入,同下
fmt.Println(sum1)
sum2 := sumUnpacking(2, 3, 5) // 可變參數函式
fmt.Println(sum2)
sum3 := sumSlice(slice) // 不曉得int長度,也可以直接包成一個slice型別來傳遞
fmt.Println(sum3)
}
func sumUnpacking(nums ...int) int { // 傳入int但不曉得參數長度為何
var total int
for _, num := range nums {
total += num
}
return total
}
func sumSlice(nums []int) int { // 傳入slice
var total int
for _, num := range nums {
total += num
}
return total
}
/* result:
10
10
10
*/
要怎麼使用 Append
來合併兩個陣列?
這邊整理了三種合併一群數字的方法。
https://play.golang.org/p/Q138HLRIuFF
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{6, 7, 8}
// 將兩 Slice 合併(append) 的方法 - 1
a1 := append(slice1, slice2[0], slice2[1], slice2[2]) // append用法,每個參數只能附上一個int
fmt.Println(a1)
// 將兩 Slice 合併(append) 的方法 - 2
a2 := slice1
for _, num := range slice2 { // 如方法1,只是這次透過for迴圈來迭代完成
a2 = append(a2, num)
}
fmt.Println(a2)
// 將兩 Slice 合併(append) 的方法 - 3
a3 := append(slice1, slice2...) // 直接將slice2 剝皮解壓縮後(Unpacking)再執行append,取代上面使用For迭代的方法
fmt.Println(a3)
}
/* result:
[1 2 3 4 5 6 7 8]
[1 2 3 4 5 6 7 8]
[1 2 3 4 5 6 7 8]
*/
這不是程式內的用法,
而是在編譯、跑測試時才會用到執行的指令
$ go test ./...
將自動運行所有這目錄底下的Package的測試程式,
當然要將所有的測試檔案 _test.go
file 先寫好,包括預設輸入及預期輸出。
GOROOT 放的是安裝的go語言、官方內建的函式庫
例如寫程式時經常會用到的"fmt"就放在這底下
import "fmt"
GOPATH 放的是別人開發的第三方套件、以及自己的程式碼
import "github.com...(別人的repository)"
照慣例通常會把自己寫的專案及程式放入GOPATH底下的**src(source)**資料夾裡,
如果有用Github會再多一層 github.com 及 account。
以上的分法都通常是在較久遠的年代,透過
glide
或dep
來管理。
自從Go 1.11
推出了gomod
後,就不一定要把專案放到GOPATH底下,也可以正常運行
但這邊還是偏向使用GOPATH
及glide套件管理工具
使用者目錄 (C:\Users\USER 或 ~/)
- Go (GOPATH) 如果底下沒有bin/pkg/src目錄,別擔心,自己新增一個
- bin (放編譯過後的可執行檔案 二進制檔案)
- pkg (放編譯過後的library)
- src (放原始碼 Source Code)
- github.com
- Jack (使用者名稱)
- HelloWorldProject (專案名稱)
- main.go (主程式)
- Tom
- MyCoolProject
- core (函式庫名稱)
- core.go
- xxxx.go
- libs (函式庫名稱)
- lib.go
- oooo.go
- main.go
- gitlab.com
- ...
專案Project、包Package 都是P開頭,傻傻分不清?
套件是別人寫好的Project或Package,只是我們把他拿來使用。
看到這邊,是時候來回顧這篇文章了 寫程式之前,GO這些很重要
gopath src 建議不要在使用
請用 go module
配合社群規範展開 project layout
看到 專案有 src 的, 我都覺得來亂得
https://github.com/golang-standards/project-layout
https://juejin.im/post/6844903565496958990
類似 ddd 的概念, 來分配目錄結構
部門自己定義好就行了吧?
DDD也能協助用來協助切割服務邊界