文章目錄
go教程
go 簡介
Go 是一個開源的編程語言,它能讓構造簡單、可靠且高效的軟件變得容易。
Go是從2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持開發,後來還加入了Ian Lance Taylor, Russ Cox等人,並最終於2009年11月開源,在2012年早些時候發佈了Go 1穩定版本。現在Go的開發已經是完全開放的,並且擁有一個活躍的社區。
相關網站:
go官網:https://golang.org/pkg/
go依賴包搜索:https://godoc.org/
go 安裝
安裝包下載地址爲:https://golang.org/dl/。
window安裝目錄默認爲:c:/go,bin目錄自動指向bin目錄。
linux解壓tgz包,將bin目錄添加到PATH變量中,假設go解壓在/opt/go目錄下
cat << 'EOF' >> ~/.bash_profile
PATH=$PATH:/opt/go/bin
export PATH
EOF
測試go是否正常安裝
C:\Users\GVT>go version
go version go1.14.2 windows/amd64
go 常用命令
直接在終端中輸入 go help 即可顯示所有的 go 命令以及相應命令功能簡介,主要有下面這些:
- build: 編譯包和依賴
- clean: 移除對象文件
- doc: 顯示包或者符號的文檔
- env: 打印go的環境信息
- bug: 啓動錯誤報告
- fix: 運行go tool fix
- fmt: 運行gofmt進行格式化
- generate: 從processing source生成go文件
- get: 下載並安裝包和依賴
- install: 編譯並安裝包和依賴
- list: 列出包
- run: 編譯並運行go程序
- test: 運行測試
- tool: 運行go提供的工具
- version: 顯示go的版本
- vet: 運行go tool vet
命令的使用方式爲: go command [args], 除此之外,可以使用go help 來顯示指定命令的更多幫助信息。
在運行 go help 時,不僅僅打印了這些命令的基本信息,還給出了一些概念的幫助信息:
- c: Go和c的相互調用
- buildmode: 構建模式的描述
- filetype: 文件類型
- gopath: GOPATH環境變量
- environment: 環境變量
- importpath: 導入路徑語法
- packages: 包列表的描述
- testflag: 測試符號描述
- testfunc: 測試函數描述
同樣使用 go help 來查看這些概念的的信息。
build 和 run 命令
就像其他靜態類型語言一樣,要執行 go 程序,需要先編譯,然後在執行產生的可執行文件。go build 命令就是用來編譯 go程序生成可執行文件的。但並不是所以的 go 程序都可以編譯生成可執行文件的, 要生成可執行文件,go程序需要滿足兩個條件:
- 該go程序需要屬於main包
- 在main包中必須還得包含main函數
也就是說go程序的入口就是 main.main, 即main包下的main函數, 例子(hello.go):
cat <<EOF > hello.go
package main
import "fmt"
func main(){
fmt.Println("Hello World")
}
EOF
編譯hello.go,然後運行可執行程序:
go build hello.go
當前目錄下生成了hello.exe,運行
GVT@DESKTOP-V14R68B MINGW64 ~/go
$ ./hello.exe
Hello World
而 go run 命令可以將上面兩步併爲一步執行(不會產生中間文件)。
$ go run hello.go
Hello World!
上面兩個命令都是在開發中非常常用的。
此外 go clean 命令,可以用於將清除產生的可執行程序:
$ go clean # 不加參數,可以刪除當前目錄下的所有可執行文件
$ go clean sourcefile.go # 會刪除對應的可執行文件
fmt 和 doc 命令
go 語言有一個褒貶不一的特性,就是對格式的要求很嚴格,我是很喜歡這個特性的,因爲可以保持代碼的清晰一致,編譯組合開發,並且go還提供了一個非常強大的工具來格式化代碼,它就是 go fmt sourcefile.go, 不過通常其實不需要我們手動調用,各種編輯器都可以幫助我們自動完成格式化。
go doc 命令可以方便我們快速查看包文檔,go doc package 命令將會在終端中打印出指定 package 的文檔。
如查看fmt文檔
go doc fmt
另外有一個與 go doc 命令相關的命令是 godoc, 可以通過它啓動我們自己的文檔服務器:
godoc -http=:8080
然後我們就可與在瀏覽器localhost:8080中查看go文檔了
godoc默認不帶可執行程序,生成可執行程序步驟
git clone https://github.com/golang/tools golang.org/x/tools
go安裝目錄/src新建golang.org\x\tools目錄 拷貝源代碼到該目錄
cd C:\Go\src\golang.org\x\tools\godoc
go build golang.org/x/tools/cmd/godoc
go install golang.org/x/tools/cmd/godoc 自動拷貝到bin目錄
install 命令
用來編譯和安裝go程序,我們可以將它與 build 命令對比:
生成的可執行文件路徑 工作目錄下的bin目錄下 當前目錄下
可執行文件的名字 與源碼所在目錄同名 默認與源程序同名,可以使用-o選項指定
依賴 將依賴的包放到工作目錄下的pkg文件夾下 -
build | build | |
---|---|---|
生成的可執行文件路徑 | 工作目錄下的bin目錄下 | 當前目錄下 |
可執行文件的名字 | 與源碼所在目錄同名 | 默認與源程序同名,可以使用-o選項指定 |
依賴 | 將依賴的包放到工作目錄下的pkg文件夾下 | - |
env 命令
查看所有環境變量
go env
go env | grep GOROOT
修改環境變量(設置中國區代理或者阿里雲代理:https://mirrors.aliyun.com/goproxy/)
go env -w GOPROXY=https://goproxy.cn
get 命令
go get 命令可以藉助代碼管理工具通過遠程拉取或更新代碼包及其依賴包,並自動完成編譯和安裝。整個過程就像安裝一個 App 一樣簡單。
這個命令可以動態獲取遠程代碼包,目前支持的有 BitBucket、GitHub、Google Code 和 Launchpad。在使用 go get 命令前,需要安裝與遠程包匹配的代碼管理工具,如 Git、SVN、HG 等,參數中需要提供一個包名。
這個命令在內部實際上分成了兩步操作:第一步是下載源碼包,第二步是執行 go install。下載源碼包的 go 工具會自動根據不同的域名調用不同的源碼工具,對應關係如下:
BitBucket (Mercurial Git)
GitHub (Git)
Google Code Project Hosting (Git, Mercurial, Subversion)
Launchpad (Bazaar)
所以爲了 go get 命令能正常工作,你必須確保安裝了合適的源碼管理工具,並同時把這些命令加入你的 PATH 中。其實 go get 支持自定義域名的功能。
參數介紹:
- -d 只下載不安裝
- -f 只有在你包含了 -u 參數的時候纔有效,不讓 -u 去驗證 import 中的每一個都已經獲取了,這對於本地 fork 的包特別有用
- -fix 在獲取源碼之後先運行 fix,然後再去做其他的事情
- -t 同時也下載需要爲運行測試所需要的包
- -u 強制使用網絡去更新包和它的依賴包
- -v 顯示執行的命令
Go語言的代碼被託管於 Github.com 網站,該網站是基於 Git 代碼管理工具的,很多有名的項目都在該網站託管代碼。其他類似的託管網站還有 code.google.com、bitbucket.org 等。
這些網站的項目包路徑都有一個共同的標準,參見下圖所示
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lZFb5vnB-1589278910682)(images/1.jpg)]
圖中的遠程包路徑是 Go語言的源碼,這個路徑共由 3 個部分組成:
- 網站域名:表示代碼託管的網站,類似於電子郵件 @ 後面的服務器地址。
- 作者或機構:表明這個項目的歸屬,一般爲網站的用戶名,如果需要找到這個作者下的所有項目,可以直接在網站上通過搜索“域名/作者”進行查看。這部分類似於電子郵件 @ 前面的部分。
- 項目名:每個網站下的作者或機構可能會同時擁有很多的項目,圖中標示的部分表示項目名稱。
默認情況下,go get 可以直接使用。例如,想獲取 go 的源碼並編譯,使用下面的命令行即可:
go get github.com/davyxu/cellnet
獲取前,請確保 GOPATH 已經設置。Go 1.8 版本之後,GOPATH 默認在用戶目錄的 go 文件夾下。
cellnet 只是一個網絡庫,並沒有可執行文件,因此在 go get 操作成功後 GOPATH 下的 bin 目錄下不會有任何編譯好的二進制文件。
需要測試獲取並編譯二進制的,可以嘗試下面的這個命令。當獲取完成後,就會自動在 GOPATH 的 bin 目錄下生成編譯好的二進制文件。
go get -u github.com/gpmgo/gopm
查看你的GOPATH/bin目錄下是否生成gopm.exe,src是否有gpmgo源碼。
go package
包的基本概念
Go語言的包藉助了目錄樹的組織形式,一般包的名稱就是其源文件所在目錄的名稱,雖然Go語言沒有強制要求包名必須和其所在的目錄名同名,但還是建議包名和所在目錄同名,這樣結構更清晰。
包可以定義在很深的目錄中,包名的定義是不包括目錄路徑的,但是包在引用時一般使用全路徑引用。比如在GOPATH/src/a/b/ 下定義一個包 c。在包 c 的源碼中只需聲明爲package c,而不是聲明爲package a/b/c,但是在導入 c 包時,需要帶上路徑,例如import “a/b/c”。
包的習慣用法:
- 包名一般是小寫的,使用一個簡短且有意義的名稱。
- 包名一般要和所在的目錄同名,也可以不同,包名中不能包含- 等特殊符號。
- 包一般使用域名作爲目錄名稱,這樣能保證包名的唯一性,比如 GitHub 項目的包一般會放到GOPATH/src/github.com/userName/projectName 目錄下。
- 包名爲 main 的包爲應用程序的入口包,編譯不包含 main 包的源碼文件時不會得到可執行文件。
一個文件夾下的所有源碼文件只能屬於同一個包,同樣屬於同一個包的源碼文件不能放在多個文件夾下。
包導入
單行導入
import "包 1 的路徑"
import "包 2 的路徑"
多行導入
import (
"包 1 的路徑"
"包 2 的路徑"
)
別名
package main
import F "fmt"
func main() {
F.Println("C語言中文網")
}
省略引用
package main
import . "fmt"
func main() {
//不需要加前綴 fmt.
Println("C語言中文網")
}
標準的Go語言代碼庫中包含了大量的包,並且在安裝 Go 的時候多數會自動安裝到系統中。我們可以在 $GOROOT/src/pkg 目錄中查看這些包。下面簡單介紹一些我們開發中常用的包。
- fmt
fmt 包實現了格式化的標準輸入輸出,這與C語言中的 printf 和 scanf 類似。其中的 fmt.Printf() 和 fmt.Println() 是開發者使用最爲頻繁的函數。
格式化短語派生於C語言,一些短語(%- 序列)是這樣使用:
- %v:默認格式的值。當打印結構時,加號(%+v)會增加字段名;
- %#v:Go樣式的值表達;
- %T:帶有類型的 Go 樣式的值表達。
- io
這個包提供了原始的 I/O 操作界面。它主要的任務是對 os 包這樣的原始的 I/O 進行封裝,增加一些其他相關,使其具有抽象功能用在公共的接口上。 - bufio
bufio 包通過對 io 包的封裝,提供了數據緩衝功能,能夠一定程度減少大塊數據讀寫帶來的開銷。
在 bufio 各個組件內部都維護了一個緩衝區,數據讀寫操作都直接通過緩存區進行。當發起一次讀寫操作時,會首先嚐試從緩衝區獲取數據,只有當緩衝區沒有數據時,纔會從數據源獲取數據更新緩衝。 - sort
sort 包提供了用於對切片和用戶定義的集合進行排序的功能。 - strconv
strconv 包提供了將字符串轉換成基本數據類型,或者從基本數據類型轉換爲字符串的功能。 - os
os 包提供了不依賴平臺的操作系統函數接口,設計像 Unix 風格,但錯誤處理是 go 風格,當 os 包使用時,如果失敗後返回錯誤類型而不是錯誤數量。 - sync
sync 包實現多線程中鎖機制以及其他同步互斥機制。 - flag
flag 包提供命令行參數的規則定義和傳入參數解析的功能。絕大部分的命令行程序都需要用到這個包。 - encoding/json
JSON 目前廣泛用做網絡程序中的通信格式。encoding/json 包提供了對 JSON 的基本支持,比如從一個對象序列化爲 JSON 字符串,或者從 JSON 字符串反序列化出一個具體的對象等。 - html/template
主要實現了 web 開發中生成 html 的 template 的一些函數。 - net/http
net/http 包提供 HTTP 相關服務,主要包括 http 請求、響應和 URL 的解析,以及基本的 http 客戶端和擴展的 http 服務。
通過 net/http 包,只需要數行代碼,即可實現一個爬蟲或者一個 Web 服務器,這在傳統語言中是無法想象的。 - reflect
reflect 包實現了運行時反射,允許程序通過抽象類型操作對象。通常用於處理靜態類型 interface{} 的值,並且通過 Typeof 解析出其動態類型信息,通常會返回一個有接口類型 Type 的對象。 - os/exec
os/exec 包提供了執行自定義 linux 命令的相關實現。 - strings
strings 包主要是處理字符串的一些函數集合,包括合併、查找、分割、比較、後綴檢查、索引、大小寫處理等等。
strings 包與 bytes 包的函數接口功能基本一致。 - bytes
bytes 包提供了對字節切片進行讀寫操作的一系列函數。字節切片處理的函數比較多,分爲基本處理函數、比較函數、後綴檢查函數、索引函數、分割函數、大小寫處理函數和子切片處理函數等。 - log
log 包主要用於在程序中輸出日誌。
log 包中提供了三類日誌輸出接口,Print、Fatal 和 Panic。
- Print 是普通輸出;
- Fatal 是在執行完 Print 後,執行 os.Exit(1);
- Panic 是在執行完 Print 後調用 panic() 方法。
包管理工具
除了go工具鏈自帶的工具比如,go build 、go vet 、go get 、 go doc 等等,還有包依賴管理工具。比如 dep等等,go 1.11 1.12 還添加了 go modules 。
一直依賴go語言被人吐槽的就是包依賴管理 和 錯誤處理方式。 社區出現了一批包依賴管理工具。
GOROOT 和GOPATH區別
兩個概念:GOROOT 和GOPATH
- GOROOT: 系統環境變量,就是我們存放下載的go語言源碼的地方(go的源碼,不是我們寫的)。
- GOPATH: 環境變量,我們的工作空間,包括bin、pkg、src。是存放我們寫的代碼以及下載的第三方代碼。
依賴,分爲內部依賴和外部依賴。
- 內部依賴:
GOPATH和GOROOT,GOROOT並不是必須要設置的,但是GOPATH必須要設置,但並不是固定不變的。本項目內部依賴就會在GOPATH 所配置的路徑下去尋找,編譯器如果找不到會報錯。總的來說內部依賴不需要太操心。
- 外部依賴包:
當我們要實現一些功能的時候,不可避免的需要一些第三方包,也統稱爲外部依賴包。go1.5之前只支持使用GOPATH來管理外部依賴包的,對比java的maven 和gradle等 簡直不太方便。
Vendor 機制引入
在go1.5release之前,我們要管理多個依賴包版本時,只能通過設置多個GOPATH,拷貝代碼來解決。比如,如果兩個工程都依賴了Beego,一個1.5,一個1.8,那麼必須設置倆GOPATH,並且還要記得切換。
go語言原生包缺陷:
-
能拉取源碼的平臺很有限,絕大多數依賴的是 github.com
-
不能區分版本,以至於令開發者以最後一項包名作爲版本劃分
-
依賴 列表/關係 無法持久化到本地,需要找出所有依賴包然後一個個 go get
-
只能依賴本地全局倉庫(GOPATH/GOROOT),無法將庫放置於局部倉庫($PROJECT_HOME/vendor)
簡單說,就是在你項目中多了一個vendor文件夾,go會把它默認作爲GOPATH。讓go編譯時,優先從項目源碼樹根目錄下的vendor目錄查找代碼(可以理解爲切了一次GOPATH),如果vendor中有,則不再去GOPATH中去查找。
社區支持vendor的包管理庫有很多,官方推薦的就有15種。
用的比較多的有dep(官方)、Godep、Govendor等等
go官方的包管理工具是dep,目前來看也是用的最多的,是官方建議使用的。
官方wiki各種對比: https://github.com/golang/go/wiki/PackageManagementTools
安裝方式也比較簡單,下載對應平臺可執行文件:https://github.com/golang/dep/releases,拷貝到GOROOT/bin目錄
在自己工作目錄下,使用 dep 初始化會報錯:
$ dep init
init failed: unable to detect the containing GOPATH: /home/zhongwei/work/my_project/go is not within a known GOPATH/src
也就是說項目開發定義在GOPATH目錄才能使用
不希望將新項目的目錄 my_project/go 加入到 GOPATH 中,覺得非常麻煩,另外看了consul源碼發現都切換到了go module,此時只好放棄dep。
Go Modules
使用 go module 管理依賴後會在項目根目錄下生成兩個文件 go.mod 和 go.sum。
go.mod 中會記錄當前項目的所依賴,文件格式如下所示:
module github.com/gosoon/audit-webhook
go 1.12
require (
github.com/elastic/go-elasticsearch v0.0.0
github.com/gorilla/mux v1.7.2
github.com/gosoon/glog v0.0.0-20180521124921-a5fbfb162a81
)
go.sum記錄每個依賴庫的版本和哈希值,文件格式如下所示:
github.com/elastic/go-elasticsearch v0.0.0 h1:Pd5fqOuBxKxv83b0+xOAJDAkziWYwFinWnBO0y+TZaA=
github.com/elastic/go-elasticsearch v0.0.0/go.mod h1:TkBSJBuTyFdBnrNqoPc54FN0vKf5c04IdM4zuStJ7xg=
github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gosoon/glog v0.0.0-20180521124921-a5fbfb162a81 h1:JP0LU0ajeawW2xySrbhDqtSUfVWohZ505Q4LXo+hCmg=
github.com/gosoon/glog v0.0.0-20180521124921-a5fbfb162a81/go.mod h1:1e0N9vBl2wPF6qYa+JCRNIZnhxSkXkOJfD2iFw3eOfg=
啓用 go module 功能
(1) go 版本 >= v1.11
(2) 設置GO111MODULE環境變量
-
要使用go module 首先要設置GO111MODULE=on,GO111MODULE 有三個值,off、on、auto,off 和 on 即關閉和開啓,auto 則會根據當前目錄下是否有 go.mod 文件來判斷是否使用 modules 功能。無論使用哪種模式,module 功能默認不在 GOPATH 目錄下查找依賴文件,所以使用 modules 功能時請設置好代理。
-
在使用 go module 時,將 GO111MODULE 全局環境變量設置爲 off,在需要使用的時候再開啓,避免在已有項目中意外引入 go module。
使用 go module 功能
對於新建項目使用 go module:
go mod init github.com/作者/項目名稱
構建項目
go build hello.go
首先需要使用 go mod vendor 將項目所有的依賴下載到本地 vendor 目錄中然後進行編譯.
如代碼中添加import
package main
import . "fmt"
import "github.com/google/uuid"
func main() {
Println("helloword")
uuid:=uuid.New()
Println(uuid)
}
執行命令(自動下載到vendor目錄)
F:\code\go\helloworld>go mod vendor
go: finding module for package github.com/google/uuid
go: downloading github.com/google/uuid v1.1.1
go: found github.com/google/uuid in github.com/google/uuid v1.1.1
go.mod中多了一行依賴
github.com/google/uuid v1.1.1
go.sum中多了
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
使用 Go 的其他包管理工具 godep、govendor、glide、dep 等都避免不了翻牆的問題,Go Modules 也是一樣,但在go.mod中可以使用replace將特定的庫替換成其他庫:
replace (
golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
)
也可以使用阿里雲的鏡像站:
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/
或者設置環境變量
export GOPROXY=https://mirrors.aliyun.com/goproxy/
go語法
變量定義
普通變量
package main
import "fmt"
type byte int8 //定義一個新的類型byte
type byteAlias = int8 //定義一個別名指向int8 實際類型還是int8
func main() {
var i, k int = 10, 100
var ife bool = false
i = 100
j := 100.5 //新變量根據值判斷類型使用:= 必須要var關鍵字 後續賦值還是使用=
j = 100.6
fmt.Print(i + k)
fmt.Print(ife)
fmt.Println(j)
ks := &i //引用指向 改了ks就等於改了i
*ks = 10
fmt.Println(*ks, i)
const js int = 100 //常量
fmt.Println(js)
const (
a = iota //引用一次累加一次 第一次是0
b = iota //1
c = iota //2
)
fmt.Println(a, b, c)
var an byte = 1
fmt.Printf("%T\n", an) //類型是main.byte
var an1 byteAlias = 1
fmt.Printf("%T\n", an1) //類型是int8
}
結構體和接口
package main
import "fmt"
/**
結構體類似於類
*/
type User struct {
userName string
userEmail string
userSex int
}
/**
定義接口,定義方法參數是string類型返回值是int類型
*/
type Phone interface {
call(string) int
}
/**
定義實現結構
*/
type Iphone struct {
}
/**
Iphone實現call方法
*/
func (iphone Iphone) call(message string) int {
fmt.Println("iphone說了:" + message)
return 1
}
func main() {
user := User{"zs", "[email protected]", 0}
fmt.Println(user.userEmail)
user1 := User{userEmail: "[email protected]"}
fmt.Println(user1.userEmail)
phone := new(Iphone)
phone.call("helloworld")
}
字符串
package main
import (
"fmt"
"strings"
)
func main() {
//字符串切割
str := "a_b_c"
var result []string = strings.Split(str, "_")
fmt.Println(result)
//字符串包含
fmt.Println(strings.Contains(str, "c"))
//字符串在另一個字符串位置 ,下標從0開始
fmt.Println(strings.Index(str, "_"))
//比較字符串 相等返回0 a<b返回-1 a>b返回1
fmt.Println(strings.Compare(str, "a_b"))
//返回某個字符串出現次數
fmt.Println(strings.Count(str, "_"))
//找到最後一個匹配字符的位置
fmt.Println(strings.LastIndex(str, "_"))
//是否某個字符開頭
fmt.Println(strings.HasPrefix(str, "a_"))
//是否某個字符結尾
fmt.Println(strings.HasSuffix(str, "a_"))
//join數組元素拼接成sep分格字符串
//[長度]定義指定長度數組,...根據值確定長度
var strlist = []string{"a", "b"}
var strlist1 = [...]string{"a", "b"}
var strlist2 [2]string
strlist2[0] = "zs"
strlist2[1] = "ls"
cc := strings.Join(strlist, ",")
fmt.Println(cc, strlist1)
//將某個字符串替換成目標字符串多少次
fmt.Println(strings.Replace(str, "_", "-", strings.Count(str, "_")))
//轉換大小寫
fmt.Println(strings.ToUpper(str), strings.ToLower(str))
//去除左右空格,去掉指定字符
fmt.Println(strings.TrimSpace(" a b "), strings.TrimLeft("_abc_", "_"))
//截取字符串 從開始索引到結束索引,包含開頭不包含結尾。
fmt.Println(str[1:2])
}
數組
package main
import "fmt"
func main() {
var k string = "a"
//初始化帶值
var arr = [...]string{"zs", "ls"}
arr1 := []string{"zs", "ls"}
arr2 := [2]string{"zs", "ls"}
fmt.Println(k, arr, arr1, arr2)
//只定義不初始化
var arr3 [3]string
arr3[0] = "zs"
//修改數組值
arr3[1] = "ls"
fmt.Println(arr3)
//獲取數組值
fmt.Println(arr3[1])
//獲取數組長度
fmt.Println(len(arr3))
//循環數組
for i := 0; i < len(arr3); i++ {
fmt.Println(i, arr3[i])
}
}
切片
package main
import "fmt"
func main() {
//可以聲明一個未指定大小的數組來定義切片:
var idList []int
//定義切片
numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
//追加numbers和10到一個新的切片中,bumbers本身不變
idList = append(numbers, 10)
fmt.Println(numbers)
fmt.Println(idList)
/* 創建切片 numbers1 是之前切片的兩倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷貝 numbers 的內容到 numbers1 */
copy(numbers1, numbers)
fmt.Println(numbers1)
}
map
package main
import "fmt"
func main() {
//var map_variable map[key_data_type]value_data_type
kvs := map[string]string{"id": "1", "name": "zs"}
fmt.Println(kvs)
a := 1
var b int = 10
for k, v := range kvs {
fmt.Println(k, v)
}
}
鏈表list
package main
import (
"container/list"
"fmt"
)
func main() {
//列表是一種非連續的存儲容器,由多個節點組成,節點通過一些變量記錄彼此之間的關係,列表有多種實現方法,如單鏈表、雙鏈表等。
userList:=list.New()
userList.PushBack("zs")
userList.PushFront("ls")
fmt.Println(userList.Len())
for i:=userList.Front();i!=nil;i=i.Next(){
fmt.Println(i.Value)
}
}
流程控制
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
in := bufio.NewReader(os.Stdin)
str, _, err := in.ReadLine()
if err != nil {
fmt.Println(err.Error())
}
if string(str) == "1" {
fmt.Print("boy")
} else {
fmt.Println("girl")
}
}
循環
package main
import "fmt"
func main() {
//初始化帶值
var arr = [...]string{"zs", "ls"}
//循環數組
for i := 0; i < len(arr); i++ {
fmt.Println(i, arr[i])
}
//range類似於foreach 參數1是索引參數2是指,不需要某個值可以使用_ ,一般用於map類型
for index, value := range arr {
fmt.Println(index, value)
}
for _, value := range arr {
fmt.Println(value)
}
//條件循環,打印1-10所有奇數
i := 0
for i < 10 {
i++
if i%2 == 0 {
continue
}
fmt.Printf("%v ", i)
}
fmt.Println()
i = 0
LOOP:
for i < 10 {
i++
if i%2 == 0 {
goto LOOP //等價於continue,也可以在任意地方定義label 根據邏輯goto
}
fmt.Printf("%v ", i)
}
}
函數
package main
import "fmt"
//func function_name( [parameter list] ) [返回值類型] {
func add(i int, j int) int {
return i + j
}
func calc(i int, j int) (int, int) {
return i + j, i - j
}
func main() {
fmt.Println(add(100, 34))
addresult, minusResult := calc(100, 34)
fmt.Println(addresult, minusResult)
}
異常處理
package main
import (
"errors"
"fmt"
)
/**
error的接口定義
type error interface {
Error() string
}
*/
/**
一般可以在函數最後一個參數添加一個錯誤參數,通過errors.New創建
*/
func div(num1 int,num2 int) (int,error){
if(num2==0){
return 0,errors.New("除數不能爲0")
}
return num1/num2,nil
}
/**
自定義異常,比如
*/
type Sex struct {
sex int;//性別只能爲0和1
}
func (sex Sex) Error() string{
return fmt.Sprintf("性別字段%v只能爲0和1", sex.sex)
}
func setSex(sex Sex)(string){
if(sex.sex!=1 && sex.sex !=0){
return sex.Error();
}
return ""
}
func main() {
result,err:=div(100,0)
if(err!=nil){
fmt.Println(err)
}else{
fmt.Println(result)
}
sex:=Sex{2}
errorMsg:=setSex(sex)
fmt.Println(errorMsg)
}