ninetyhe
格式
程序統(tǒng)?使? ”gofmt“ 進(jìn)行格式化;如果使用的IDE是Goland可以按照如下進(jìn)行配置:PrePerences -> Tools -> FileWatcher(如果沒(méi)有在plugins安裝) :添加 go fmt;
推薦一并添加:golangci-lint 和 goimports。這樣就可以進(jìn)?語(yǔ)法檢查和?動(dòng)處理導(dǎo)入和刪除包注釋
// ?注釋?式,?于簡(jiǎn)單的方法和字段注釋
/* */ 塊注釋方式叭喜,本書(shū)推薦在每一個(gè)包前面注釋?zhuān)f(shuō)明該包的主要作用
? /*
? function: do xxx
? */
? package regexp
名字
Go語(yǔ)?言的命名?小寫(xiě)跨晴,決定了該方法或者該類(lèi)是否公有還是私有,本書(shū)推薦如果?法不對(duì)外調(diào)用根吁,首字?建議小寫(xiě)员淫,如果需要跨包調(diào)?則?字?需要大寫(xiě);
包的命名統(tǒng)一使?用小寫(xiě),并且不應(yīng)該使?下劃線或者駝峰击敌。(這點(diǎn)表示有點(diǎn)別扭介返,如果名字真的過(guò)長(zhǎng)的話,可讀性會(huì)很差) Get/Set:Go不提供對(duì)Get和Set支持沃斤,但是推薦?己實(shí)現(xiàn)圣蝎,但是對(duì)于Get建議直接??字母代替,例如:如果你有一個(gè)域叫做owner(?寫(xiě)轰枝,不被導(dǎo)出)捅彻,則Get方法應(yīng)該叫做 Owner (大寫(xiě),被導(dǎo)出)鞍陨,?不是 GetOwner (個(gè)人覺(jué)得有點(diǎn)反人類(lèi)步淹,?且protobuf generate 的pb文件的字段也是是 Getxx )。這里聯(lián)想到?前我們??用的gRPC诚撵,看到很多同學(xué)的字段命名都是大駝峰的缭裆,開(kāi)始還以為gRPC有特殊不同的規(guī)范,后來(lái)查閱了官網(wǎng)更加肯定寿烟,對(duì)象的屬性要?駝峰澈驼,字段的訪問(wèn)需要通過(guò)Get和Set來(lái)訪問(wèn)!?法命名:單個(gè)方法的接?口使?方法名加上“er”后綴來(lái)命名,或者類(lèi)似的修改來(lái)構(gòu)造?個(gè)施動(dòng)者名詞
分號(hào)
Go語(yǔ)?省略分號(hào); {} 中的左 { 不能換行;條件語(yǔ)句省略 ()
控制結(jié)構(gòu)
Go中的循環(huán)結(jié)構(gòu)只用 for 語(yǔ)句筛武,主要分為以下三種:
// 傳統(tǒng)的for寫(xiě)法 for init; condition; post { }
// 對(duì)應(yīng)其他語(yǔ)言中 while for condition { }
//?直循環(huán) for { }
函數(shù)
?持多返回值缝其,Go語(yǔ)?支持函數(shù)返回多個(gè)返回值,本書(shū)推薦也給返回值命名徘六,這樣對(duì)于以下int值對(duì)應(yīng)哪
個(gè)就值就??了然 例例如:
func (file *File) Write(b []byte) (n int, m int, err error)
延時(shí)執(zhí)行defer;這是一種不不尋常但又很有效的方法内边,?于處理類(lèi)似于不管函數(shù)通過(guò)哪個(gè)執(zhí)行路徑返回,
資源都必須要被釋放的情況待锈。經(jīng)常?用于鏈接斷開(kāi)漠其,釋放鎖或者關(guān)閉IO如果需要將?些值初始化,或者在代碼執(zhí)行前調(diào)?,可以在 init 函數(shù)實(shí)現(xiàn),該函數(shù)會(huì)優(yōu)先被執(zhí)?;
數(shù)據(jù)
Go語(yǔ)?言使?new和make分配原語(yǔ); new ?于給T類(lèi)型的分配內(nèi)存和屎,但是并不會(huì)初始化內(nèi)存拴驮,只是將其置為0; make 不同于 new ,它用于創(chuàng)建 silence 柴信, map 和 channel 套啤,并返回一個(gè)初始化(?不是置0),類(lèi)型給T的值颠印。如果需要獲得一個(gè)顯式的指針纲岭,就必須只?用 new 分配。
構(gòu)造器 :本書(shū)推薦結(jié)構(gòu)體的屬性值盡量不要有空或者空线罕,通過(guò)構(gòu)造?對(duì)其初始化;
數(shù)組 :在Go中:數(shù)組是值止潮。將?個(gè)數(shù)組賦值給另一個(gè),會(huì)拷?所有的元素;特別是钞楼,如果你給函數(shù)傳遞?個(gè)數(shù)組喇闸,其將收到一個(gè)數(shù)組的拷貝,?不是它的指針;組的大小是其類(lèi)型的一部分询件。類(lèi)型
[10]int 和 [20]int 是不同的燃乍。
切片 :切?持有對(duì)底層數(shù)組的引用,如果你將?個(gè)切?賦值給另?個(gè)宛琅,?者都將引用同?個(gè)數(shù)組刻蟹,或你將切片的值進(jìn)行修改,則原數(shù)組的內(nèi)容也將發(fā)?改變
字典 :同切片一樣嘿辟,map持有對(duì)底層數(shù)據(jù)結(jié)構(gòu)的引用舆瘪。如果將map傳遞給函數(shù),其對(duì)map的內(nèi)容做了改變红伦,則這些改變對(duì)于調(diào)?者是可?的英古。如果像判斷Map釋放包含該元素,需要使用 :
//感覺(jué)好蠢昙读,并沒(méi)有像Java那樣有contains key或者contains value召调,//如果像?便使?且避免代碼寫(xiě)成一坨,建議??實(shí)現(xiàn)一個(gè)?法收斂該邏輯if value,ok := map[key];ok{
// if exist do some
}
//?不建議使?以下?式:value, ret := map1["key"]
if ret == true{
fmt.Print("map1[\"key\"]存在蛮浑,值為:", i)
} else {
fmt.Print("map1[\"key\"],不存在\n")
}
初始化
常量 在編譯的時(shí)候就被創(chuàng)建唠叛,并且只能是數(shù)字,字符(附文)沮稚,字符串或者布爾類(lèi)型玻墅。由于編譯限制,
表達(dá)式必須為能被編譯器求值的常量表達(dá)式壮虫, 例如:// 常量表達(dá)式
1<<3
// ?常量表達(dá)式,在const不可使用math.Sin(math.Pi/4)
init函數(shù) 如果需要將一些值初始化,或者需要預(yù)先調(diào)??法函數(shù)囚似,可以在 int 函數(shù)中實(shí)現(xiàn);例如:
func init() {
//需要初始化調(diào)用方法
initFunction(a interface{},b interface{})
// 初始化變量
initParam
}
接?
通過(guò)法與接口剩拢,Go語(yǔ)?定義了一種與java/C++等OOP語(yǔ)言截然不同的“繼承”的形態(tài)。通過(guò)實(shí)現(xiàn)接口定
義的方法饶唤,便可將reciever的類(lèi)型變量賦值給接?類(lèi)型變量徐伐,通過(guò)接?類(lèi)型變量來(lái)調(diào)用到reciever類(lèi)型的
?法 例如:
//定義了一個(gè)接口geometry表示幾何類(lèi)型type thisIsInterface interface {
? ? funcA() int32
? ? funcB(bool)
}
//實(shí)現(xiàn)類(lèi)實(shí)現(xiàn)兩個(gè)方法type IntImpl struct {
A, B float64
}
//在Go中,實(shí)現(xiàn)接?募狂,只需要實(shí)現(xiàn)該接口定義的所有方法即可
//A接口方法實(shí)現(xiàn)
? func (r * IntImpl) funcA(res float64) {
? ? A *= res
? ? B *= res
}
func (r * IntImpl) funcB() float64 {
? ? return r.A * r.B
}
//可以把rect和circle類(lèi)型的變量量作為實(shí)參
//傳遞給geometry接口類(lèi)型的變量
func measure (i thisIsInterface){
? ? fmt.Print("i 's area:",i.funcA(),"\n")
? ? i.funcB(2)
? ? fmt.Print("after funcB , funcA :",i.funcA(),"\n")
}
func main() {
? ? i := IntImpl{A: 10, B: 5}
? ? measure(&i)
}
并發(fā)
Gorutine 輕量級(jí)并發(fā)的函數(shù)執(zhí)行線索办素,創(chuàng)建開(kāi)銷(xiāo)初始化棧空間?較?祸穷,會(huì)根據(jù)實(shí)際需要堆的空間分配或
者釋放額外空間Gorutine與操作系統(tǒng)線程間采用“多對(duì)多”的映射?方式性穿,其他Gorutines不會(huì)因?yàn)槠渲?一個(gè)Gorutines阻塞后
?阻塞
在函數(shù)前加 go 關(guān)鍵字就可以創(chuàng)建?個(gè)Gorutine并調(diào)?該函數(shù)?法。當(dāng)該函數(shù)執(zhí)行完成之后隱式推出(類(lèi)似于Java中的 Thread )
Channel:于map類(lèi)似雷滚,也是通過(guò) make 進(jìn)?行行分配需曾,如果創(chuàng)建的時(shí)候指定?小,如果?零則即創(chuàng)建一個(gè)
緩沖區(qū)祈远。如果是零呆万,則是?無(wú)緩沖的channel或同步channel
例例如:
stringBuffer := make(chan string,10)
value := <- stringBuffer
并行實(shí)現(xiàn)方式:可以創(chuàng)建多個(gè)go func 并行執(zhí)?多個(gè)函數(shù),然后通過(guò)sync.WaitGroup來(lái)實(shí)現(xiàn)阻塞等并?的結(jié)果(類(lèi)似于Java中的 CountDownlunch )车份,但是功能相當(dāng)簡(jiǎn)陋陋谋减,功能相差更更遠(yuǎn)
互斥: 通過(guò)sync.Mutex可以創(chuàng)建鎖進(jìn)行互斥,例例如:
import (
"sync"
"runtime"
"fmt"
)
var {
//共享變量
num int
wg sync.WaitGroup
//鎖
lock sync.Mutex
}
func Add(){
? ? defer wg.Done()
? ? for count := 0;ciunt < 2; count++{
? ? ? ? // lock
}
}
lock.Lock()
{
? ? value := num
? ? value++
? ? num = value
}
// release lock
lock.Unlock()
func main{
? ? wg.Add(2)
? ? go Add()
? ? go Add()
? ? wg.Wait()
? ? fmt.Printf("result is : %d\n", num)
}
結(jié)果如下:
result is : 4
類(lèi)型斷?
Go?面對(duì)類(lèi)型判斷有兩種: value扫沼,ok := element.(T) 當(dāng)然也可以直接這樣用 (不推
薦) value:=element.(T) 這樣的話出爹,?旦出錯(cuò)就會(huì)產(chǎn)?運(yùn)?錯(cuò)誤,不推薦使用;