Base

  • GOROOT: golang的安裝路徑
  • GOPATH: 工作目錄
  • "_": 空白標(biāo)識符

Go 不是像 C ++封拧,Java,Ruby 和 C#一樣的面向?qū)ο蟮模∣O)語言。它沒有對象和繼承的概念,也沒有很多與面向?qū)ο笙嚓P(guān)的概念,例如多態(tài)和重載止后。

Go沒有類或者說面向?qū)ο蟮母拍? 結(jié)構(gòu)體就是Go里面的類

鏡像復(fù)制

func main() {
goku := Saiyan{"Power", 9000}
Super(goku)
fmt.Println(goku.Power)
}

func Super(s Saiyan) {
s.Power += 10000
}
上面程序運(yùn)行的結(jié)果是 9000,而不是 19000,溜腐。為什么译株?因?yàn)?Super 修改了原始值 goku 的復(fù)制版本,而不是它本身

&: 取地址符

func main() {
goku := &Saiyan{"Power", 9000}
Super(goku)
fmt.Println(goku.Power)
}

func Super(s *Saiyan) {
s.Power += 10000
}

這里注意到我們?nèi)匀粋鬟f了一個 goku 的值的副本給 Super挺益,但這時 goku 的值其實(shí)是一個地址歉糜。所以這個副本值也是一個與原值相等的地址,
這就是我們間接傳值的方式望众。想象一下匪补,就像復(fù)制一個指向飯店的方向牌伞辛。你所擁有的是一個方向牌的副本,但是它仍然指向原來的飯店夯缺。

復(fù)制一個指針比復(fù)制一個復(fù)雜的結(jié)構(gòu)的消耗小多了

Go結(jié)構(gòu)體使用組合的方式, 代替面向?qū)ο笾械睦^承

指針類型和值類型(指針類型就是類似對象了, 分配在堆上的內(nèi)存)

當(dāng)不確定要用值還是指針時, 就用指針

數(shù)組

在 Go 中蚤氏,像其它大部分語言一樣,數(shù)據(jù)的長度是固定的踊兜。我們在聲明一個數(shù)組時需要指定它的長度竿滨,一旦指定了長度,那么它的長度值是不可以改變的了

var scores [10]int
scores[0] = 339

數(shù)組非常高效但是很死板

切片

在 Go 語言中捏境,我們很少直接使用數(shù)組于游。取而代之的是使用切片。切片是輕量的包含并表示數(shù)組的一部分的結(jié)構(gòu)垫言。

//和數(shù)組聲明不同的是贰剥,我們的切片沒有在方括號中定義長度
scores := []int{1,4,293,4,9}
  • make方式創(chuàng)建切片
    scores := make([]int, 10)
    1. 使用 make 關(guān)鍵字代替 new, 是因?yàn)閯?chuàng)建一個切片不僅是只分配一段內(nèi)存(這個是 new 關(guān)鍵字的功能)筷频。
    2. 具體來講蚌成,我們必須要為一個底層數(shù)組分配一段內(nèi)存,同時也要初始化這個切片截驮。
    3. 上面的代碼中笑陈,我們初始化了一個長度是 10 ,容量是 10 的切片
    4. 長度是切片的長度葵袭,容量是底層數(shù)組的長度
    5. 在使用 make 創(chuàng)建切片時,我們可以分別的指定切片的長度和容量:scores := make([]int, 0, 10)
    6. 上面的代碼創(chuàng)建了一個長度是 0 乖菱,容量是 10 的切片

理解切片的長度和容量之間的關(guān)系

切片就是從數(shù)組切一段下來, 切片的長度就是標(biāo)識切了多長的數(shù)組, 容量就是底層數(shù)組的長度
我們可以調(diào)整的切片大小最大范圍是多少呢坡锡?達(dá)到它的容量, 就像例子中的10
這實(shí)際上并沒有解決數(shù)組固定長度的問題。但是 append 是相當(dāng)特別的窒所。如果底層數(shù)組滿了鹉勒,它將創(chuàng)建一個更大的數(shù)組并且復(fù)制所有原切片中的值
Go 使用 2x 算法來增加數(shù)組長度(加倍容量)

四種方式創(chuàng)建切片

  1. names := []string{"leto", "jessica", "paul"} //字面量方式
  2. checks := make([]bool, 10) //知道容量
  3. var names []string //創(chuàng)建空切片
  4. scores := make([]int, 0, 20) //創(chuàng)建指定容量的切片

切片的內(nèi)存理解

其他語言的切片 ---> 一個切片實(shí)際上是復(fù)制了原始值的新數(shù)組。

scores = [1,2,3,4,5]
slice = scores[2..4]
slice[0] = 999
puts scores
//答案是 [1, 2, 3, 4, 5] 吵取。那是因?yàn)?slice 是一個新數(shù)組禽额,并且復(fù)制了原有的值。

Go ---> 切片是指向原始數(shù)組的指針

scores := []int{1,2,3,4,5}
slice := scores[2:4]
slice[0] = 999
fmt.Println(scores)
//輸出是 [1, 2, 999, 4, 5]

只有顯示的使用copy內(nèi)建函數(shù), 才會復(fù)制新數(shù)組

總結(jié)
// 數(shù)組是連續(xù)存儲的空間 切片只存放指針 沒有存放數(shù)據(jù) 所以 指針的位置
// 只收上界影響皮官,也就是數(shù)據(jù)的基址脯倒, 他的操作范圍 只能從指針開始到連續(xù)的內(nèi)存結(jié)束 如果超過容量 擴(kuò)容后
// 就產(chǎn)生了新的數(shù)組和內(nèi)存空間 切片的指針也會指向新的內(nèi)存

映射

看錯了, 以為是反射
映射就是字典, 使用 make 方法來創(chuàng)建

  • 使用 len 方法類獲取映射的鍵的數(shù)量
  • 使用 delete 方法來刪除一個鍵對應(yīng)的值
  • 映射是動態(tài)變化的
  • 通過傳遞第二個參數(shù)到 make 方法來設(shè)置一個初始大小(如果你事先知道映射會有多少鍵值,定義一個初始大小將會幫助改善性能捺氢。)

包管理

在 Go 語言中藻丢,包名遵循 Go 項(xiàng)目的目錄結(jié)構(gòu)。(意思是目錄就是包名)

  1. 循環(huán)導(dǎo)入問題
  2. 可見性, 如果類型和函數(shù)的名字是大寫就是外界可見的, 小寫的名字就是外界不可見
  3. go get 庫鏈接(會把下載下來的庫, 放在工作目錄GOPATH)
  4. 依賴管理 go get -u 包更新

go get的缺點(diǎn): 無法指定版本

接口

目前為止摄乒,我們看到的類型都是具體的類型悠反,一個具體的類型可以準(zhǔn)確的描述它所代表的值残黑。而接口類型是一種抽象的類型。它不會暴露出它所代表的對象的內(nèi)部值的結(jié)構(gòu)和這個對象支持的基礎(chǔ)操作的集合斋否;它們只會表現(xiàn)出它們自己的方法梨水。也就是說當(dāng)你有看到一個接口類型的值時,你不知道它是什么茵臭,唯一知道的就是可以通過它的方法來做什么疫诽。

type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
    ...
}

  • interface可以被任意的對象實(shí)現(xiàn)
  • 一個對象可以實(shí)現(xiàn)任意多個interface
  • 任意的類型都實(shí)現(xiàn)了空interface(我們這樣定義:interface{}),也就是包含0個method的interface

接口有助于將代碼與特定的實(shí)現(xiàn)進(jìn)行分離(按照iOS的Delegate來理解)

接口就是一種協(xié)議笼恰,和現(xiàn)實(shí)中的接口一個道理踊沸。
一提到usbc你就知道那個接口長什么樣,但是你不關(guān)心usbc芯片是什么樣的社证,怎么接線逼龟。
代碼通過接口定義來表明自己對外開放的能力,具體的實(shí)現(xiàn)則交給實(shí)現(xiàn)這個接口的類追葡。
只要實(shí)現(xiàn)了這個接口的類腺律,都一定存在對應(yīng)的方法,那么我拿到這個類的實(shí)例對象的時候宜肉,就一定可以調(diào)用這個對象所實(shí)現(xiàn)的方法匀钧。
具體的好處需要多實(shí)踐才好領(lǐng)會,
比如ios編程常見的委托谬返,java常用的控制反轉(zhuǎn)之類之斯。
如果寫過http接口,實(shí)際上也是一樣的道理遣铝。

type Logger interface {
Log(message string)
}

錯誤處理

Go 首選錯誤處理方式是返回值佑刷,而不是異常。

作為最后一點(diǎn)酿炸,Go 確實(shí)有 panic 和 recover 函數(shù)瘫絮。 panic 就像拋出異常,而 recover 就像 catch填硕,它們很少使用麦萤。

defer

盡管 Go 有一個垃圾回收器,一些資源仍然需要我們顯式地釋放他們扁眯。例如壮莹,我們需要在使用完文件之后 Close() 他們。
這種代碼總是很危險(xiǎn)恋拍。一方面來說垛孔,當(dāng)我們在寫一個函數(shù)的時候,很容易忘記關(guān)閉我們聲明了 10 行的東西施敢。
另一方面周荐,一個函數(shù)可能有多個返回點(diǎn)狭莱。Go 給出的解決方案是使用 defer 關(guān)鍵字:

無論什么情況,在函數(shù)返回之后(本例中為 main() )概作,defer 將被執(zhí)行腋妙。這使您可以在初始化的位置附近釋放資源并處理多個返回點(diǎn)。

go fmt

格式化代碼
當(dāng)你在一個項(xiàng)目內(nèi)的時候讯榕,你可以運(yùn)用格式化規(guī)則到這個項(xiàng)目及其所有子目錄:
go fmt ./...

空接口和轉(zhuǎn)換

字符串和字節(jié)數(shù)組

函數(shù)類型

函數(shù)是一種類型:
type Add func(a int, b int) int
可以作為參數(shù)傳遞

并發(fā)

Go 通常被描述為一種并發(fā)友好的語言骤素。 原因是它提供了兩種強(qiáng)大機(jī)制的簡單語法: 協(xié)程 和 通道

package main

import (
  "fmt"
  "time"
)

func main() {
  fmt.Println("start")
  go process()
  time.Sleep(time.Millisecond * 10) // this is bad, don't do this!
  fmt.Println("done")
}

func process() {
  fmt.Println("processing")
}
  • 開始一個 協(xié)程 。 我們只需使用 go 關(guān)鍵字愚屁,然后使用我們想要執(zhí)行的函數(shù)济竹。
  • 協(xié)程 易于創(chuàng)建且開銷很小。最終多個 協(xié)程 將會在同一個底層的操作系統(tǒng)線程上運(yùn)行霎槐。 這通常也稱為 M:N 線程模型送浊,因?yàn)槲覀冇?M 個應(yīng)用線程( 協(xié)程 )運(yùn)行在 N 個操作系統(tǒng)線程上。結(jié)果就是丘跌,一個 協(xié)程 的開銷和系統(tǒng)線程比起來相對很低(幾 KB)袭景。在現(xiàn)代的硬件上,有可能擁有數(shù)百萬個 協(xié)程 闭树。

同步

并發(fā)編程中的問題:

  1. 變量會被其他線程讀寫, 如果保證讀寫安全
  2. 加鎖的效率問題: 需要個優(yōu)雅的鎖操作耸棒; 否則,我們最終會把多條快速通道走成單車道的报辱。
  3. 加鎖死鎖的問題: 當(dāng)協(xié)程 A 擁有鎖 lockA 与殃,想去訪問鎖 lockB ,同時協(xié)程 B 擁有鎖 lockB 并需要訪問鎖 lockA 碍现。

解決辦法:

  1. 有一個常見的鎖叫讀寫互斥鎖奈籽。它主要提供了兩種鎖功能:一個鎖定讀取和一個鎖定寫入。它的區(qū)別是允許多個同時讀取鸵赫,同時確保寫入是獨(dú)占的。在 Go 中躏升, sync.RWMutex 就是這種鎖辩棒。
  2. 通道 旨在讓并發(fā)編程更簡潔和不容易出錯。(加鎖容易出問題)

通道

而Go是通過一種特殊的類型膨疏,通道(channel)一睁,一個可以用于發(fā)送類型化數(shù)據(jù)的管道,由其負(fù)責(zé)協(xié)程之間的通信佃却,從而避開所有由共享內(nèi)存導(dǎo)致的陷阱者吁;這種通過通道進(jìn)行通信的方式保證了同步性。數(shù)據(jù)在通道中進(jìn)行傳遞:在任何給定時間饲帅,一個數(shù)據(jù)被設(shè)計(jì)為只有一個協(xié)程可以對其訪問复凳,所以不會發(fā)生數(shù)據(jù)競爭瘤泪。 數(shù)據(jù)的所有權(quán)(可以讀寫數(shù)據(jù)的能力)也因此被傳遞。

  • 通道操作符 <-

并發(fā)編程的最大調(diào)整源于數(shù)據(jù)的共享育八。如跨多個請求共享數(shù)據(jù)对途。內(nèi)存緩存和數(shù)據(jù)庫

  • 通道是協(xié)程之間用于傳遞數(shù)據(jù)的管道

換而言之,一個協(xié)程可以通過一個通道向另外一個協(xié)程傳遞數(shù)據(jù)髓棋。因此实檀,在任意時間點(diǎn),只有一個協(xié)程可以訪問數(shù)據(jù)按声。

  • 一個通道膳犹,和其他任何變量一樣,都有一個類型,這個類型是在通道中傳遞的數(shù)據(jù)的類型签则。例如须床,創(chuàng)建一個通道用于傳遞一個整數(shù),我們要這樣做:
c := make(chan int)
  • 通道只支持兩個操作:接收和發(fā)送怀愧。
  • 接收和發(fā)送操作是阻塞的侨颈。

也就是,當(dāng)我們從一個通道接收的時候芯义, goroutine 將會直到數(shù)據(jù)可用才會繼續(xù)執(zhí)行哈垢。類似地,當(dāng)我們往通道發(fā)送數(shù)據(jù)的時候扛拨,goroutine 會等到數(shù)據(jù)接收到之后才會繼續(xù)執(zhí)行耘分。

  • Go 保證了發(fā)送到通道的數(shù)據(jù)只會被一個接收器接收。(保證多線程數(shù)據(jù)安全, 讀寫的唯一)

通道阻塞

默認(rèn)情況下绑警,通信是同步且無緩沖的:在有接受者接收數(shù)據(jù)之前求泰,發(fā)送不會結(jié)束。

一個無緩沖的通道在沒有空間來保存數(shù)據(jù)的時候:必須要一個接收者準(zhǔn)備好接收通道的數(shù)據(jù)然后發(fā)送者可以直接把數(shù)據(jù)發(fā)送給接收者计盒。
所以通道的發(fā)送/接收操作在對方準(zhǔn)備好之前是阻塞的:

  1. 對于同一個通道渴频,發(fā)送操作(協(xié)程或者函數(shù)中的)在接收者準(zhǔn)備好之前是阻塞的:如果ch中的數(shù)據(jù)無人接收,就無法再給通道傳入其他數(shù)據(jù):新的輸入無法在通道非空的情況下傳入北启。所以發(fā)送操作會等待 ch 再次變?yōu)榭捎脿顟B(tài):就是通道值被接收時就可以再傳入變量卜朗。
  2. 對于同一個通道,接收操作是阻塞的(協(xié)程或函數(shù)中的)咕村,直到發(fā)送者可用:如果通道中沒有數(shù)據(jù)场钉,接收者就阻塞了。

緩沖通道

一個無緩沖通道只能包含 1 個元素懈涛,有時顯得很局限逛万。我們給通道提供了一個緩存,可以在擴(kuò)展的 make 命令中設(shè)置它的容量

buf := 100
ch1 := make(chan string, buf)
  • 在緩沖滿載(緩沖被全部使用)之前批钠,給一個帶緩沖的通道發(fā)送數(shù)據(jù)是不會阻塞的宇植,而從通道讀取數(shù)據(jù)也不會阻塞得封,直到緩沖空了。
  • 緩沖容量和類型無關(guān)当纱,所以可以給一些通道設(shè)置不同的容量呛每,只要他們擁有同樣的元素類型。內(nèi)置的 cap 函數(shù)可以返回緩沖區(qū)的容量坡氯。
  • 如果容量大于 0晨横,通道就是異步的:因?yàn)榫彌_滿載(發(fā)送)或變空(接收)之前通信不會阻塞,元素會按照發(fā)送的順序被接收箫柳。
  • 如果容量是0或者未設(shè)置手形,通道就是同步的:通信僅在收發(fā)雙方準(zhǔn)備好的情況下才可以成功。

通道注意事項(xiàng):

  1. channel 在 Golang 中是一等公民悯恍,它是線程安全的库糠,面對并發(fā)問題,應(yīng)首先想到 channel
  2. 關(guān)閉一個未初始化的 channel 會產(chǎn)生 panic
  3. 重復(fù)關(guān)閉同一個 channel 會產(chǎn)生 panic
  4. 向一個已關(guān)閉的 channel 發(fā)送消息會產(chǎn)生 panic
  5. 從已關(guān)閉的 channel 讀取消息不會產(chǎn)生 panic涮毫,且能讀出 channel 中還未被讀取的消息瞬欧,若消息均已被讀取,則會讀取到該類型的零值罢防。
  6. 從已關(guān)閉的 channel 讀取消息永遠(yuǎn)不會阻塞艘虎,并且會返回一個為 false 的值,用以判斷該 channel 是否已關(guān)閉(x,ok := <- ch)
  7. 關(guān)閉 channel 會產(chǎn)生一個廣播機(jī)制咒吐,所有向 channel 讀取消息的 goroutine 都會收到消息

Select

select 是 Go 中的一個控制結(jié)構(gòu)野建。select 語句類似于 switch 語句,但是select會隨機(jī)執(zhí)行一個可運(yùn)行的case恬叹。如果沒有case可運(yùn)行候生,它將阻塞,直到有case可運(yùn)行绽昼。

Select語句的作用(注意:它僅能用于channel的相關(guān)操作,select 里的 case 表達(dá)式要求是對信道的操作)

當(dāng)我們需要同時從多個通道接收數(shù)據(jù)時唯鸭,如果通道里沒有數(shù)據(jù)將會發(fā)生阻塞。為了應(yīng)對這種場景硅确,Go內(nèi)置了select關(guān)鍵字肿孵,可以同時響應(yīng)多個通道的操作。

package main

import (
    "fmt"
)

func main() {
    c1 := make(chan string, 1)
    c2 := make(chan string, 1)

    c2 <- "hello"

    select {
    case msg1 := <-c1:
        fmt.Println("c1 received: ", msg1)
    case msg2 := <-c2:
        fmt.Println("c2 received: ", msg2)
    default:
        fmt.Println("No data received.")
    }
}
//c2 received:  hello

select語句的處理邏輯:case隨機(jī)選擇處理列出的多個通信情況中的一個

  • 如果都阻塞了疏魏,會等待直到其中一個可以處理
  • 如果多個可以處理,隨機(jī)選擇一個
  • 為了避免死鎖晤愧,應(yīng)該編寫default分支或手動實(shí)現(xiàn)超時機(jī)制大莫,否則select 整體就會一直阻塞
  1. select 的 case 是隨機(jī)的,而 switch 里的 case 是順序執(zhí)行官份;
  2. select 里沒有類似 switch 里的 fallthrough 的用法只厘;
  3. select 里的 case 表達(dá)式要求是對信道的操作烙丛,不能像 switch 一樣接函數(shù)或其他表達(dá)式;

超時

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末羔味,一起剝皮案震驚了整個濱河市河咽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赋元,老刑警劉巖忘蟹,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異搁凸,居然都是意外死亡媚值,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門护糖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褥芒,“玉大人,你說我怎么就攤上這事嫡良∶谭觯” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵寝受,是天一觀的道長坷牛。 經(jīng)常有香客問我,道長羡蛾,這世上最難降的妖魔是什么漓帅? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮痴怨,結(jié)果婚禮上忙干,老公的妹妹穿的比我還像新娘。我一直安慰自己浪藻,他們只是感情好捐迫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著爱葵,像睡著了一般施戴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上萌丈,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天赞哗,我揣著相機(jī)與錄音,去河邊找鬼辆雾。 笑死肪笋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播藤乙,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼猜揪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坛梁?” 一聲冷哼從身側(cè)響起而姐,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎划咐,沒想到半個月后拴念,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尖殃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年丈莺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片送丰。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡缔俄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出器躏,到底是詐尸還是另有隱情俐载,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布登失,位于F島的核電站遏佣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏揽浙。R本人自食惡果不足惜状婶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望馅巷。 院中可真熱鬧膛虫,春花似錦、人聲如沸钓猬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敞曹。三九已至账月,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澳迫,已是汗流浹背局齿。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橄登,地道東北人项炼。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓担平,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锭部。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容