安裝和環(huán)境配置
自行百度解決
go項目的目錄結(jié)構(gòu)
go命令依賴一個重要的環(huán)境變量:$GOPATH
一般的,一個Go項目在GOPATH下,會有如下三個目錄:
|--bin
|--pkg
|--src
其中,bin存放編譯后的可執(zhí)行文件;pkg存放編譯后的包文件;src存放項目源文件。一般,bin和pkg目錄可以不創(chuàng)建,go命令會自動創(chuàng)建(如 go install),只需要創(chuàng)建src目錄即可。
go基礎(chǔ)數(shù)據(jù)類型類型
bool 類型
true false
數(shù)字類型
整型
無符號:uint8 uint16 uint32 uint64
有符號:int8 int16 int32 int64
浮點型
float32 float64
復數(shù)型
complex64 complex128
一些別稱類型
byte -- uint8
rune -- int32
uint int 對應(yīng)CPU平臺機器字大小的無符號和有符號類型
uintptr 無符號整形,用于存放一個指針,一般用于底層和C語言對接
string類型
字符串是一個不可改變的字節(jié)序列,可以包含任意數(shù)據(jù)。文本字符串通常被解釋為采用UTF-8編碼的Unicode碼點半序列。
string的操作
- 內(nèi)置函數(shù)len()返回一個字符串中的字節(jié)數(shù)目
- 索引操作s[i]返回第i個字節(jié)的字節(jié)值,i必須滿足0 ≤ i< len(s)條件約束,否則會引發(fā)一個panic
- 子字符串操作s[i:j]基于原始的s字符串的第i個字節(jié)開始到第j個字節(jié)(并不包含j本身)生成一個新字符串。參見python的切片操作
- '+' 操作符可以將兩個字符串拼接在一起構(gòu)造一個新的字符串
fmt.Println("goodbye" + ", world") // "goodbye, world"
- 字符串可以用==和<進行比較;比較通過逐個字節(jié)比較完成的,因此比較的結(jié)果是字符串自然編碼的順序
- 字符串的值不可變,嘗試修改字符串內(nèi)部數(shù)據(jù)的操作會引發(fā)一個error
- 字符串變量的是可變的
- 字符串處理常用的標準庫包bytes、strings、strconv、unicode
常量與變量
常量 一個簡單值的標識符,在程序運行時不會被修改的量,數(shù)據(jù)類型只可能是布爾型、數(shù)字型和字符串型。定義格式如下:
const identifier [type] = value
- iota常量 自行研究
變量
聲明方法
var v_name v_type
var v_name = value
v_name := value
第一種,指定變量類型,聲明后若不賦值,使用默認值。
第二種,根據(jù)值自行判定變量類型。
第三種,省略var, 注意 :=左側(cè)的變量不應(yīng)該是已經(jīng)聲明過的,否則會導致編譯錯誤。注意,第三種簡短聲明形式只能用于函數(shù)內(nèi),全局變量不允許使用這種聲明形式。
值類型和引用類型
基本數(shù)字類型和布爾類型都是值類型,這些類型的變量直接指向存在內(nèi)存中的值。用等號進行賦值操作時,實際上是對值進行了拷貝。
一個引用類型的指針指向的是地址。
‘_’標識符
次標識符用于拋棄值,因為在Go語言中,某一變量被聲明但是未被調(diào)用會報錯,所以引入此變量可以規(guī)避這個問題。
基礎(chǔ)結(jié)構(gòu)
代碼組成
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
go語言基礎(chǔ)組成分為以下幾部分:
- 包聲明
第一行代碼 package main 定義了包名。你必須在源文件中非注釋的第一行指明這個文件屬于哪個包,如:package main。package main表示一個可獨立執(zhí)行的程序,每個 Go 應(yīng)用程序都包含一個名為 main 的包。 - 引入包
import "fmt" 告訴 Go 編譯器這個程序需要使用 fmt 包(的函數(shù),或其他元素),fmt 包實現(xiàn)了格式化 IO(輸入/輸出)的函數(shù) - 函數(shù)
下一行 func main() 是程序開始執(zhí)行的函數(shù)。main 函數(shù)是每一個可執(zhí)行程序所必須包含的,一般來說都是在啟動后第一個執(zhí)行的函數(shù)(如果有 init() 函數(shù)則會先執(zhí)行該函數(shù))
執(zhí)行流程

包的概念
包是結(jié)構(gòu)化代碼的一種方式:每個程序都由包(通常簡稱為 pkg)的概念組成,可以使用自身的包或者從其它包中導入內(nèi)容。
如同其它一些編程語言中的類庫或命名空間的概念,每個 Go 文件都屬于且僅屬于一個包。
在 Go 的安裝文件里包含了一些可以直接使用的包,即標準庫。
Go 中的包模型采用了顯式依賴關(guān)系的機制來達到快速編譯的目的,如果 A.go 依賴 B.go,而 B.go 又依賴 C.go:
編譯 C.go, B.go, 然后是 A.go.
為了編譯 A.go, 編譯器讀取的是 B.o 而不是 C.o.
這種機制對于編譯大型的項目時可以顯著地提升編譯速度。
如果導入一個包但是沒有使用,在編譯時會引發(fā)錯誤。
可見性
參見C++的公私有成員。
當標識符(包括常量、變量、類型、函數(shù)名、結(jié)構(gòu)字段等等)以一個大寫字母開頭,如:Group1,那么使用這種形式的標識符的對象就可以被外部包的 代碼所使用(客戶端程序需要先導入這個包),這被稱為導出(像面向?qū)ο笳Z言中的 public);標識符如果以小寫字母開頭,則對包外是不可見的,但是他們在整個包的內(nèi)部是可見并且可用的(像面向?qū)ο笳Z言中的 private )。
go系統(tǒng)工具
常用的命令工具
好像都挺常用的,主要介紹以下幾個:
- go build
go build 命令主要是用于測試編譯。在包的編譯過程中,若有必要,會同時編譯與之相關(guān)聯(lián)的包。
如果是普通包,當你執(zhí)行g(shù)o build命令后,不會產(chǎn)生任何文件。
如果是main包,當只執(zhí)行g(shù)o build命令后,會在當前目錄下生成一個可執(zhí)行文件。
go build 會忽略目錄下以”_”或者”.”開頭的go文件。 - go fmt
go fmt 命令主要是用來幫你格式化所寫好的代碼文件。 - go get
go get 命令主要是用來動態(tài)獲取遠程代碼包的。
go get 命令本質(zhì)上可以理解為:首先通過源碼工具clone代碼到src目錄,然后執(zhí)行g(shù)o install。
復合數(shù)據(jù)類型
以不同的方式組合基本類型可以構(gòu)造出來的復合數(shù)據(jù)類型。
主要討論四種類型——數(shù)組、slice、map和結(jié)構(gòu)體。
數(shù)組和結(jié)構(gòu)體是聚合類型;它們的值由許多元素或成員字段的值組成。數(shù)組是由同構(gòu)的元素組成——每個數(shù)組元素都是完全相同的類型——結(jié)構(gòu)體則是由異構(gòu)的元素組成的。數(shù)組和結(jié)構(gòu)體都是有固定內(nèi)存大小的數(shù)據(jù)結(jié)構(gòu)。相比之下,slice和map則是動態(tài)的數(shù)據(jù)結(jié)構(gòu),它們將根據(jù)需要動態(tài)增長。
數(shù)組
數(shù)組是一個由固定長度的特定類型元素組成的序列,一個數(shù)組可以由零個或多個元素組成。
- 數(shù)組的每個元素可以通過索引下標來訪問,索引下標的范圍是從0開始到數(shù)組長度減1的位置。內(nèi)置的len函數(shù)將返回數(shù)組中元素的個數(shù)。
- 默認情況下,數(shù)組的每個元素都被初始化為元素類型對應(yīng)的零值。我們也可以使用數(shù)組字面值語法用一組值來初始化數(shù)組:
var q [3]int = [3]int{1, 2, 3}
var r [3]int = [3]int{1, 2}
fmt.Println(r[2]) // "0"
- 在數(shù)組字面值中,如果在數(shù)組的長度位置出現(xiàn)的是“...”省略號,則表示數(shù)組的長度是根據(jù)初始化值的個數(shù)來計算。
q := [...]int{1, 2, 3}
- 數(shù)組的長度是數(shù)組類型的一個組成部分,因此[3]int和[4]int是兩種不同的數(shù)組類型。數(shù)組的長度必須是常量表達式,因為數(shù)組的長度需要在編譯階段確定。
- 如果數(shù)組類型相同,數(shù)組元素類型相同,可以用"=="來比較。
slice
Slice(切片)代表變長的序列,序列中每個元素都有相同的類型。一個slice類型一般寫作[]T,其中T代表slice中元素的類型;slice的語法和數(shù)組很像,只是沒有固定長度而已。slice的底層引用一個數(shù)組對象。
- 一個slice由三個部分構(gòu)成:指針、長度和容量。
- 指針指向第一個slice元素對應(yīng)的底層數(shù)組元素的地址。
- 長度對應(yīng)slice中元素的數(shù)目;長度不能超過容量,容量一般是從slice的開始位置到底層數(shù)據(jù)的結(jié)尾位置。內(nèi)置的len和cap函數(shù)分別返回slice的長度和容量。
- slice的切片操作s[i:j],其中0 ≤ i≤ j≤ cap(s),用于創(chuàng)建一個新的slice,引用s的從第i個元素開始到第j-1個元素的子序列。新的slice將只有j-i個元素。
- slice和數(shù)組的字面值語法很類似,它們都是用花括弧包含一系列的初始化元素,但是對于slice并沒有指明序列的長度。這會隱式地創(chuàng)建一個合適大小的數(shù)組,然后slice的指針指向底層的數(shù)組。
s := []int{0, 1, 2, 3, 4, 5}
- 復制一個slice只是對底層的數(shù)組創(chuàng)建了一個新的slice別名。
- 和數(shù)組不同的是,slice之間不能比較,因此我們不能使用==操作符來判斷兩個slice是否含有全部相等元素。slice唯一合法的比較操作是和nil比較,一個零值的slice等于nil。一個nil值的slice并沒有底層數(shù)組。一個nil值的slice的長度和容量都是0。
if s== nil { /* ... */ }
- 內(nèi)置的append函數(shù)用于向slice追加元素。每次調(diào)用append函數(shù),必須先檢測slice底層數(shù)組是否有足夠的容量來保存新添加的元素。如果有足夠空間的話,直接擴展slice,將新添加的元素復制到新擴展的空間,并返回slice。此時底層數(shù)組沒有改變。如果沒有足夠的增長空間,append會進行內(nèi)存擴展,分配一個足夠大的sliace空間存放原來的內(nèi)容,再把新增的內(nèi)容添加進去。我們不能確認在原先的slice上的操作是否會影響到新的slice,因此,通常是將append返回的結(jié)果直接賦值給輸入的slice變量:
runes = append(runes, r)
map
參照python的字典類型,map是一個無序的key/value對的集合,其中所有的key都是不同的,然后通過給定的key可以在常數(shù)時間復雜度內(nèi)檢索、更新或刪除對應(yīng)的value。map類型可以寫為map[K]V,其中K和V分別對應(yīng)key和value。
- map中所有的key都有相同的類型,所有的value也有著相同的類型,但是key和value之間可以是不同的數(shù)據(jù)類型。其中K對應(yīng)的key必須是支持==比較運算符的數(shù)據(jù)類型,所以map可以通過測試key是否相等來判斷是否已經(jīng)存在。
- 常用操作,創(chuàng)建,存儲,訪問,查找,刪除
創(chuàng)建可以使用內(nèi)置函數(shù)make來創(chuàng)建,也可以使用map字面值語法來創(chuàng)建。訪問方式通過key對應(yīng)的下標語法訪問。刪除操作使用內(nèi)置函數(shù)delete,delete會查找該元素,如果查找失敗將返回value類型對應(yīng)的零值,所以這種操作是安全的,即使map中不存在要刪除的元素也沒關(guān)系。
ages := make(map[string]int) // mapping from strings to ints
ages := map[string]int{
"alice": 31,
"charlie": 34,
}
ages["alice"] = 32
fmt.Println(ages["alice"]) // "32"
delete(ages, "alice") // remove element ages["alice"]
- 和slice一樣,map之間也不能進行相等比較;唯一的例外是和nil進行比較。如果我們需要對map進行比較操作,需要自己通過循環(huán)進行實現(xiàn)。
結(jié)構(gòu)體
參見C語言的結(jié)構(gòu)體,結(jié)構(gòu)體是一種聚合的數(shù)據(jù)類型,是由零個或多個任意類型的值聚合成的實體。每個值稱為結(jié)構(gòu)體的成員。例:
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
var dilbert Employee
dilbert結(jié)構(gòu)體變量的成員可以通過點操作符訪問,比如dilbert.Name和dilbert.DoB。
通常一行對應(yīng)一個結(jié)構(gòu)體成員,成員的名字在前類型在后,不過如果相鄰的成員類型如果相同的話可以被合并到一行,就像下面的Name和Address成員那樣:
type Employee struct {
ID int
Name, Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
- 結(jié)構(gòu)體類型的零值是每個成員都對是零值。
- 如果結(jié)構(gòu)體的全部成員都是可以比較的,那么結(jié)構(gòu)體也是可以比較的,那樣的話兩個結(jié)構(gòu)體將可以使用==或!=運算符進行比較。