安裝和環(huán)境配置
自行百度解決
go項(xiàng)目的目錄結(jié)構(gòu)
go命令依賴一個(gè)重要的環(huán)境變量:$GOPATH
一般的径簿,一個(gè)Go項(xiàng)目在GOPATH下只嚣,會(huì)有如下三個(gè)目錄:
|--bin
|--pkg
|--src
其中穗椅,bin存放編譯后的可執(zhí)行文件蔓倍;pkg存放編譯后的包文件全肮;src存放項(xiàng)目源文件敞咧。一般,bin和pkg目錄可以不創(chuàng)建辜腺,go命令會(huì)自動(dòng)創(chuàng)建(如 go install)休建,只需要?jiǎng)?chuàng)建src目錄即可。
go基礎(chǔ)數(shù)據(jù)類型類型
bool 類型
true false
數(shù)字類型
整型
無(wú)符號(hào):uint8 uint16 uint32 uint64
有符號(hào):int8 int16 int32 int64
浮點(diǎn)型
float32 float64
復(fù)數(shù)型
complex64 complex128
一些別稱類型
byte -- uint8
rune -- int32
uint int 對(duì)應(yīng)CPU平臺(tái)機(jī)器字大小的無(wú)符號(hào)和有符號(hào)類型
uintptr 無(wú)符號(hào)整形评疗,用于存放一個(gè)指針测砂,一般用于底層和C語(yǔ)言對(duì)接
string類型
字符串是一個(gè)不可改變的字節(jié)序列,可以包含任意數(shù)據(jù)百匆。文本字符串通常被解釋為采用UTF-8編碼的Unicode碼點(diǎn)半序列砌些。
string的操作
- 內(nèi)置函數(shù)len()返回一個(gè)字符串中的字節(jié)數(shù)目
- 索引操作s[i]返回第i個(gè)字節(jié)的字節(jié)值,i必須滿足0 ≤ i< len(s)條件約束加匈,否則會(huì)引發(fā)一個(gè)panic
- 子字符串操作s[i:j]基于原始的s字符串的第i個(gè)字節(jié)開(kāi)始到第j個(gè)字節(jié)(并不包含j本身)生成一個(gè)新字符串存璃。參見(jiàn)python的切片操作
- '+' 操作符可以將兩個(gè)字符串拼接在一起構(gòu)造一個(gè)新的字符串
fmt.Println("goodbye" + ", world") // "goodbye, world"
- 字符串可以用==和<進(jìn)行比較宙彪;比較通過(guò)逐個(gè)字節(jié)比較完成的,因此比較的結(jié)果是字符串自然編碼的順序
- 字符串的值不可變有巧,嘗試修改字符串內(nèi)部數(shù)據(jù)的操作會(huì)引發(fā)一個(gè)error
- 字符串變量的是可變的
- 字符串處理常用的標(biāo)準(zhǔn)庫(kù)包bytes、strings悲没、strconv篮迎、unicode
常量與變量
常量 一個(gè)簡(jiǎn)單值的標(biāo)識(shí)符,在程序運(yùn)行時(shí)不會(huì)被修改的量示姿,數(shù)據(jù)類型只可能是布爾型甜橱、數(shù)字型和字符串型。定義格式如下:
const identifier [type] = value
- iota常量 自行研究
變量
聲明方法
var v_name v_type
var v_name = value
v_name := value
第一種栈戳,指定變量類型岂傲,聲明后若不賦值,使用默認(rèn)值子檀。
第二種镊掖,根據(jù)值自行判定變量類型。
第三種褂痰,省略var, 注意 :=左側(cè)的變量不應(yīng)該是已經(jīng)聲明過(guò)的亩进,否則會(huì)導(dǎo)致編譯錯(cuò)誤。注意缩歪,第三種簡(jiǎn)短聲明形式只能用于函數(shù)內(nèi)归薛,全局變量不允許使用這種聲明形式。
值類型和引用類型
基本數(shù)字類型和布爾類型都是值類型匪蝙,這些類型的變量直接指向存在內(nèi)存中的值主籍。用等號(hào)進(jìn)行賦值操作時(shí),實(shí)際上是對(duì)值進(jìn)行了拷貝逛球。
一個(gè)引用類型的指針指向的是地址千元。
‘_’標(biāo)識(shí)符
次標(biāo)識(shí)符用于拋棄值,因?yàn)樵贕o語(yǔ)言中需忿,某一變量被聲明但是未被調(diào)用會(huì)報(bào)錯(cuò)诅炉,所以引入此變量可以規(guī)避這個(gè)問(wèn)題。
基礎(chǔ)結(jié)構(gòu)
代碼組成
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
go語(yǔ)言基礎(chǔ)組成分為以下幾部分:
- 包聲明
第一行代碼 package main 定義了包名屋厘。你必須在源文件中非注釋的第一行指明這個(gè)文件屬于哪個(gè)包涕烧,如:package main。package main表示一個(gè)可獨(dú)立執(zhí)行的程序汗洒,每個(gè) Go 應(yīng)用程序都包含一個(gè)名為 main 的包议纯。 - 引入包
import "fmt" 告訴 Go 編譯器這個(gè)程序需要使用 fmt 包(的函數(shù),或其他元素)溢谤,fmt 包實(shí)現(xiàn)了格式化 IO(輸入/輸出)的函數(shù) - 函數(shù)
下一行 func main() 是程序開(kāi)始執(zhí)行的函數(shù)瞻凤。main 函數(shù)是每一個(gè)可執(zhí)行程序所必須包含的憨攒,一般來(lái)說(shuō)都是在啟動(dòng)后第一個(gè)執(zhí)行的函數(shù)(如果有 init() 函數(shù)則會(huì)先執(zhí)行該函數(shù))
執(zhí)行流程
包的概念
包是結(jié)構(gòu)化代碼的一種方式:每個(gè)程序都由包(通常簡(jiǎn)稱為 pkg)的概念組成,可以使用自身的包或者從其它包中導(dǎo)入內(nèi)容阀参。
如同其它一些編程語(yǔ)言中的類庫(kù)或命名空間的概念肝集,每個(gè) Go 文件都屬于且僅屬于一個(gè)包。
在 Go 的安裝文件里包含了一些可以直接使用的包蛛壳,即標(biāo)準(zhǔn)庫(kù)杏瞻。
Go 中的包模型采用了顯式依賴關(guān)系的機(jī)制來(lái)達(dá)到快速編譯的目的,如果 A.go 依賴 B.go衙荐,而 B.go 又依賴 C.go:
編譯 C.go, B.go, 然后是 A.go.
為了編譯 A.go, 編譯器讀取的是 B.o 而不是 C.o.
這種機(jī)制對(duì)于編譯大型的項(xiàng)目時(shí)可以顯著地提升編譯速度捞挥。
如果導(dǎo)入一個(gè)包但是沒(méi)有使用,在編譯時(shí)會(huì)引發(fā)錯(cuò)誤忧吟。
可見(jiàn)性
參見(jiàn)C++的公私有成員砌函。
當(dāng)標(biāo)識(shí)符(包括常量、變量溜族、類型讹俊、函數(shù)名、結(jié)構(gòu)字段等等)以一個(gè)大寫字母開(kāi)頭煌抒,如:Group1劣像,那么使用這種形式的標(biāo)識(shí)符的對(duì)象就可以被外部包的 代碼所使用(客戶端程序需要先導(dǎo)入這個(gè)包),這被稱為導(dǎo)出(像面向?qū)ο笳Z(yǔ)言中的 public)摧玫;標(biāo)識(shí)符如果以小寫字母開(kāi)頭耳奕,則對(duì)包外是不可見(jiàn)的,但是他們?cè)谡麄€(gè)包的內(nèi)部是可見(jiàn)并且可用的(像面向?qū)ο笳Z(yǔ)言中的 private )诬像。
go系統(tǒng)工具
常用的命令工具
好像都挺常用的屋群,主要介紹以下幾個(gè):
- go build
go build 命令主要是用于測(cè)試編譯。在包的編譯過(guò)程中坏挠,若有必要芍躏,會(huì)同時(shí)編譯與之相關(guān)聯(lián)的包。
如果是普通包降狠,當(dāng)你執(zhí)行g(shù)o build命令后对竣,不會(huì)產(chǎn)生任何文件。
如果是main包榜配,當(dāng)只執(zhí)行g(shù)o build命令后否纬,會(huì)在當(dāng)前目錄下生成一個(gè)可執(zhí)行文件。
go build 會(huì)忽略目錄下以”_”或者”.”開(kāi)頭的go文件蛋褥。 - go fmt
go fmt 命令主要是用來(lái)幫你格式化所寫好的代碼文件临燃。 - go get
go get 命令主要是用來(lái)動(dòng)態(tài)獲取遠(yuǎn)程代碼包的。
go get 命令本質(zhì)上可以理解為:首先通過(guò)源碼工具clone代碼到src目錄,然后執(zhí)行g(shù)o install膜廊。
復(fù)合數(shù)據(jù)類型
以不同的方式組合基本類型可以構(gòu)造出來(lái)的復(fù)合數(shù)據(jù)類型乏沸。
主要討論四種類型——數(shù)組、slice爪瓜、map和結(jié)構(gòu)體蹬跃。
數(shù)組和結(jié)構(gòu)體是聚合類型;它們的值由許多元素或成員字段的值組成铆铆。數(shù)組是由同構(gòu)的元素組成——每個(gè)數(shù)組元素都是完全相同的類型——結(jié)構(gòu)體則是由異構(gòu)的元素組成的炬转。數(shù)組和結(jié)構(gòu)體都是有固定內(nèi)存大小的數(shù)據(jù)結(jié)構(gòu)。相比之下算灸,slice和map則是動(dòng)態(tài)的數(shù)據(jù)結(jié)構(gòu),它們將根據(jù)需要?jiǎng)討B(tài)增長(zhǎng)驻啤。
數(shù)組
數(shù)組是一個(gè)由固定長(zhǎng)度的特定類型元素組成的序列菲驴,一個(gè)數(shù)組可以由零個(gè)或多個(gè)元素組成。
- 數(shù)組的每個(gè)元素可以通過(guò)索引下標(biāo)來(lái)訪問(wèn)骑冗,索引下標(biāo)的范圍是從0開(kāi)始到數(shù)組長(zhǎng)度減1的位置赊瞬。內(nèi)置的len函數(shù)將返回?cái)?shù)組中元素的個(gè)數(shù)。
- 默認(rèn)情況下贼涩,數(shù)組的每個(gè)元素都被初始化為元素類型對(duì)應(yīng)的零值巧涧。我們也可以使用數(shù)組字面值語(yǔ)法用一組值來(lái)初始化數(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ù)組的長(zhǎng)度位置出現(xiàn)的是“...”省略號(hào)遥倦,則表示數(shù)組的長(zhǎng)度是根據(jù)初始化值的個(gè)數(shù)來(lái)計(jì)算谤绳。
q := [...]int{1, 2, 3}
- 數(shù)組的長(zhǎng)度是數(shù)組類型的一個(gè)組成部分,因此[3]int和[4]int是兩種不同的數(shù)組類型袒哥。數(shù)組的長(zhǎng)度必須是常量表達(dá)式缩筛,因?yàn)閿?shù)組的長(zhǎng)度需要在編譯階段確定。
- 如果數(shù)組類型相同堡称,數(shù)組元素類型相同瞎抛,可以用"=="來(lái)比較。
slice
Slice(切片)代表變長(zhǎng)的序列却紧,序列中每個(gè)元素都有相同的類型桐臊。一個(gè)slice類型一般寫作[]T,其中T代表slice中元素的類型晓殊;slice的語(yǔ)法和數(shù)組很像断凶,只是沒(méi)有固定長(zhǎng)度而已。slice的底層引用一個(gè)數(shù)組對(duì)象巫俺。
- 一個(gè)slice由三個(gè)部分構(gòu)成:指針懒浮、長(zhǎng)度和容量。
- 指針指向第一個(gè)slice元素對(duì)應(yīng)的底層數(shù)組元素的地址。
- 長(zhǎng)度對(duì)應(yīng)slice中元素的數(shù)目砚著;長(zhǎng)度不能超過(guò)容量次伶,容量一般是從slice的開(kāi)始位置到底層數(shù)據(jù)的結(jié)尾位置。內(nèi)置的len和cap函數(shù)分別返回slice的長(zhǎng)度和容量稽穆。
- slice的切片操作s[i:j]冠王,其中0 ≤ i≤ j≤ cap(s),用于創(chuàng)建一個(gè)新的slice舌镶,引用s的從第i個(gè)元素開(kāi)始到第j-1個(gè)元素的子序列柱彻。新的slice將只有j-i個(gè)元素。
- slice和數(shù)組的字面值語(yǔ)法很類似餐胀,它們都是用花括弧包含一系列的初始化元素哟楷,但是對(duì)于slice并沒(méi)有指明序列的長(zhǎng)度。這會(huì)隱式地創(chuàng)建一個(gè)合適大小的數(shù)組否灾,然后slice的指針指向底層的數(shù)組卖擅。
s := []int{0, 1, 2, 3, 4, 5}
- 復(fù)制一個(gè)slice只是對(duì)底層的數(shù)組創(chuàng)建了一個(gè)新的slice別名。
- 和數(shù)組不同的是墨技,slice之間不能比較惩阶,因此我們不能使用==操作符來(lái)判斷兩個(gè)slice是否含有全部相等元素。slice唯一合法的比較操作是和nil比較扣汪,一個(gè)零值的slice等于nil断楷。一個(gè)nil值的slice并沒(méi)有底層數(shù)組。一個(gè)nil值的slice的長(zhǎng)度和容量都是0崭别。
if s== nil { /* ... */ }
- 內(nèi)置的append函數(shù)用于向slice追加元素冬筒。每次調(diào)用append函數(shù),必須先檢測(cè)slice底層數(shù)組是否有足夠的容量來(lái)保存新添加的元素茅主。如果有足夠空間的話账千,直接擴(kuò)展slice,將新添加的元素復(fù)制到新擴(kuò)展的空間暗膜,并返回slice匀奏。此時(shí)底層數(shù)組沒(méi)有改變。如果沒(méi)有足夠的增長(zhǎng)空間学搜,append會(huì)進(jìn)行內(nèi)存擴(kuò)展娃善,分配一個(gè)足夠大的sliace空間存放原來(lái)的內(nèi)容,再把新增的內(nèi)容添加進(jìn)去瑞佩。我們不能確認(rèn)在原先的slice上的操作是否會(huì)影響到新的slice聚磺,因此,通常是將append返回的結(jié)果直接賦值給輸入的slice變量:
runes = append(runes, r)
map
參照python的字典類型炬丸,map是一個(gè)無(wú)序的key/value對(duì)的集合瘫寝,其中所有的key都是不同的蜒蕾,然后通過(guò)給定的key可以在常數(shù)時(shí)間復(fù)雜度內(nèi)檢索、更新或刪除對(duì)應(yīng)的value焕阿。map類型可以寫為map[K]V咪啡,其中K和V分別對(duì)應(yīng)key和value。
- map中所有的key都有相同的類型暮屡,所有的value也有著相同的類型撤摸,但是key和value之間可以是不同的數(shù)據(jù)類型。其中K對(duì)應(yīng)的key必須是支持==比較運(yùn)算符的數(shù)據(jù)類型褒纲,所以map可以通過(guò)測(cè)試key是否相等來(lái)判斷是否已經(jīng)存在准夷。
- 常用操作,創(chuàng)建莺掠,存儲(chǔ)衫嵌,訪問(wèn),查找彻秆,刪除
創(chuàng)建可以使用內(nèi)置函數(shù)make來(lái)創(chuàng)建楔绞,也可以使用map字面值語(yǔ)法來(lái)創(chuàng)建。訪問(wèn)方式通過(guò)key對(duì)應(yīng)的下標(biāo)語(yǔ)法訪問(wèn)掖棉。刪除操作使用內(nèi)置函數(shù)delete,delete會(huì)查找該元素膀估,如果查找失敗將返回value類型對(duì)應(yīng)的零值幔亥,所以這種操作是安全的,即使map中不存在要?jiǎng)h除的元素也沒(méi)關(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之間也不能進(jìn)行相等比較;唯一的例外是和nil進(jìn)行比較饼记。如果我們需要對(duì)map進(jìn)行比較操作香伴,需要自己通過(guò)循環(huán)進(jìn)行實(shí)現(xiàn)。
結(jié)構(gòu)體
參見(jiàn)C語(yǔ)言的結(jié)構(gòu)體具则,結(jié)構(gòu)體是一種聚合的數(shù)據(jù)類型即纲,是由零個(gè)或多個(gè)任意類型的值聚合成的實(shí)體。每個(gè)值稱為結(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)體變量的成員可以通過(guò)點(diǎn)操作符訪問(wèn)低斋,比如dilbert.Name和dilbert.DoB。
通常一行對(duì)應(yīng)一個(gè)結(jié)構(gòu)體成員匪凡,成員的名字在前類型在后膊畴,不過(guò)如果相鄰的成員類型如果相同的話可以被合并到一行,就像下面的Name和Address成員那樣:
type Employee struct {
ID int
Name, Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
- 結(jié)構(gòu)體類型的零值是每個(gè)成員都對(duì)是零值病游。
- 如果結(jié)構(gòu)體的全部成員都是可以比較的唇跨,那么結(jié)構(gòu)體也是可以比較的,那樣的話兩個(gè)結(jié)構(gòu)體將可以使用==或!=運(yùn)算符進(jìn)行比較。