go語言入門教程01-go工具+go語法+go module

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 目錄中查看這些包。下面簡單介紹一些我們開發中常用的包。

  1. fmt
    fmt 包實現了格式化的標準輸入輸出,這與C語言中的 printf 和 scanf 類似。其中的 fmt.Printf() 和 fmt.Println() 是開發者使用最爲頻繁的函數。
    格式化短語派生於C語言,一些短語(%- 序列)是這樣使用:
  • %v:默認格式的值。當打印結構時,加號(%+v)會增加字段名;
  • %#v:Go樣式的值表達;
  • %T:帶有類型的 Go 樣式的值表達。
  1. io
    這個包提供了原始的 I/O 操作界面。它主要的任務是對 os 包這樣的原始的 I/O 進行封裝,增加一些其他相關,使其具有抽象功能用在公共的接口上。
  2. bufio
    bufio 包通過對 io 包的封裝,提供了數據緩衝功能,能夠一定程度減少大塊數據讀寫帶來的開銷。
    在 bufio 各個組件內部都維護了一個緩衝區,數據讀寫操作都直接通過緩存區進行。當發起一次讀寫操作時,會首先嚐試從緩衝區獲取數據,只有當緩衝區沒有數據時,纔會從數據源獲取數據更新緩衝。
  3. sort
    sort 包提供了用於對切片和用戶定義的集合進行排序的功能。
  4. strconv
    strconv 包提供了將字符串轉換成基本數據類型,或者從基本數據類型轉換爲字符串的功能。
  5. os
    os 包提供了不依賴平臺的操作系統函數接口,設計像 Unix 風格,但錯誤處理是 go 風格,當 os 包使用時,如果失敗後返回錯誤類型而不是錯誤數量。
  6. sync
    sync 包實現多線程中鎖機制以及其他同步互斥機制。
  7. flag
    flag 包提供命令行參數的規則定義和傳入參數解析的功能。絕大部分的命令行程序都需要用到這個包。
  8. encoding/json
    JSON 目前廣泛用做網絡程序中的通信格式。encoding/json 包提供了對 JSON 的基本支持,比如從一個對象序列化爲 JSON 字符串,或者從 JSON 字符串反序列化出一個具體的對象等。
  9. html/template
    主要實現了 web 開發中生成 html 的 template 的一些函數。
  10. net/http
    net/http 包提供 HTTP 相關服務,主要包括 http 請求、響應和 URL 的解析,以及基本的 http 客戶端和擴展的 http 服務。
    通過 net/http 包,只需要數行代碼,即可實現一個爬蟲或者一個 Web 服務器,這在傳統語言中是無法想象的。
  11. reflect
    reflect 包實現了運行時反射,允許程序通過抽象類型操作對象。通常用於處理靜態類型 interface{} 的值,並且通過 Typeof 解析出其動態類型信息,通常會返回一個有接口類型 Type 的對象。
  12. os/exec
    os/exec 包提供了執行自定義 linux 命令的相關實現。
  13. strings
    strings 包主要是處理字符串的一些函數集合,包括合併、查找、分割、比較、後綴檢查、索引、大小寫處理等等。
    strings 包與 bytes 包的函數接口功能基本一致。
  14. bytes
    bytes 包提供了對字節切片進行讀寫操作的一系列函數。字節切片處理的函數比較多,分爲基本處理函數、比較函數、後綴檢查函數、索引函數、分割函數、大小寫處理函數和子切片處理函數等。
  15. 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)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章