Go 語言的基礎組成有以下幾個部分:包聲明 引入包 函數(shù) 變量 語句 & 表達式 注釋
當標識符(包括常量鸽粉、變量、類型聋呢、函數(shù)名苗踪、結(jié)構字段等等)以一個大寫字母開頭,如:Group1削锰,那么使用這種形式的標識符的對象就可以被外部包的代碼所使用(客戶端程序需要先導入這個包)通铲,這被稱為導出(像面向?qū)ο笳Z言中的 public);標識符如果以小寫字母開頭器贩,則對包外是不可見的测暗,但是他們在整個包的內(nèi)部是可見并且可用的(像面向?qū)ο笳Z言中的 protected )。
在 Go 程序中磨澡,一行代表一個語句結(jié)束碗啄。每個語句不需要像 C 家族中的其它語言一樣以分號 ; 結(jié)尾,因為這些工作都將由 Go 編譯器自動完成稳摄。如果你打算將多個語句寫在同一行稚字,它們則必須使用 ; 人為區(qū)分,但在實際開發(fā)中我們并不鼓勵這種做法厦酬。
Go 語言按類別有以下幾種數(shù)據(jù)類型:
序號 類型和描述
1 布爾型
布爾型的值只可以是常量 true 或者 false胆描。一個簡單的例子:var b bool = true。
2 數(shù)字類型
整型 int 和浮點型 float32仗阅、float64昌讲,Go 語言支持整型和浮點型數(shù)字,并且支持復數(shù)减噪,其中位的運算采用補碼短绸。
3 字符串類型:
字符串就是一串固定長度的字符連接起來的字符序列车吹。Go 的字符串是由單個字節(jié)連接起來的。Go 語言的字符串的字節(jié)使用 UTF-8 編碼標識 Unicode 文本醋闭。
4 派生類型:
包括:
(a) 指針類型(Pointer)
(b) 數(shù)組類型
(c) 結(jié)構化類型(struct)
(d) Channel 類型
(e) 函數(shù)類型
(f) 切片類型
(g) 接口類型(interface)
(h) Map 類型
變量聲明
第一種窄驹,指定變量類型,如果沒有初始化证逻,則變量默認為零值乐埠。
數(shù)值類型(包括complex64/128)為 0? 例如:var b int
布爾類型為 false例如:var c bool
字符串為 ""(空字符串)例如:var a string
其他幾種類型為 nil:例如:var a []int
第二種,根據(jù)值自行判定變量類型囚企。
var d = true
第三種丈咐,省略 var, 注意 := 左側(cè)如果沒有聲明新的變量,就產(chǎn)生編譯錯誤龙宏,格式:
v_name := value
常量的定義格式:
const identifier [type] = value
你可以省略類型說明符 [type]扯罐,因為編譯器可以根據(jù)變量的值來推斷其類型。
顯式類型定義: const b string = "abc"
隱式類型定義: const b = "abc"
多個常量的聲明可以簡寫為:
const c_name1, c_name2 = value1, value2
其他運算符:
& 返回變量存儲地址 &a; 將給出變量的實際地址烦衣。
* 指針變量歹河。 *a; 是一個指針變量
Go 沒有三目運算符,所以不支持 ?: 形式的條件判斷花吟。
Go 語言的 For 循環(huán)有 3 中形式秸歧,只有其中的一種使用分號。
和 C 語言的 for 一樣:
for init; condition; post { }
例如:
func main() {
? ? ? ? sum := 0
? ? ? ? for i := 0; i <= 10; i++ {
? ? ? ? ? ? ? ? sum += i
? ? ? ? }
? ? ? ? fmt.Println(sum)
}
和 C 的 while 一樣:
for condition { }
和 C 的 for(;;) 一樣:
for { }
Go 語言函數(shù)定義格式如下:
func function_name( [parameter list] ) [return_types] {
? ?函數(shù)體
}
例如:
/* 函數(shù)返回兩個數(shù)的最大值 */
func max(num1, num2 int) int {
? ?/* 聲明局部變量 */
? ?var result int
? ?if (num1 > num2) {
? ? ? result = num1
? ?} else {
? ? ? result = num2
? ?}
? ?return result?
}
函數(shù)返回多個值
Go 函數(shù)可以返回多個值衅澈,例如:
實例
package main
import "fmt"
func swap(x, y string) (string, string) {
? ?return y, x
}
func main() {
? ?a, b := swap("Google", "Runoob")
? ?fmt.Println(a, b)
}
Go 語言變量作用域
局部變量:在函數(shù)體內(nèi)聲明的變量稱之為局部變量键菱,它們的作用域只在函數(shù)體內(nèi),參數(shù)和返回值變量也是局部變量今布。
全局變量:在函數(shù)體外聲明的變量稱之為全局變量经备,全局變量可以在整個包甚至外部包(被導出后)使用。
聲明數(shù)組
Go 語言數(shù)組聲明需要指定元素類型及元素個數(shù)部默,語法格式如下:
var variable_name [SIZE] variable_type
例如:var balance [10] float32
初始化數(shù)組:var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
Go 語言切片(Slice)
Go 語言切片是對數(shù)組的抽象侵蒙。
Go 數(shù)組的長度不可改變,在特定場景中這樣的集合就不太適用傅蹂,Go中提供了一種靈活纷闺,功能強悍的內(nèi)置類型切片("動態(tài)數(shù)組"),與數(shù)組相比切片的長度是不固定的,可以追加元素份蝴,在追加時可能使切片的容量增大犁功。
定義切片(切片不需要說明長度)
你可以聲明一個未指定大小的數(shù)組來定義切片:
var identifier []type
或使用make()函數(shù)來創(chuàng)建切片:
var slice1 []type = make([]type, len)? ? ?也可以簡寫為 slice1 := make([]type, len)
也可以指定容量,其中capacity為可選參數(shù)婚夫。
make([]T, length, capacity)
goroutine:
是go語言并發(fā)執(zhí)行的模型浸卦。比線程更輕量,因為多個goroutine可以復用同一個線程案糙,當一個goroutine等待io時限嫌,該線程上的其他goroutine可以繼續(xù)執(zhí)行靴庆,所以goroutine其實是一種纖程。
channel:
channel 是 goroutine 之間通信的一種方式
channel 的讀寫操作
ch := make(chan int)
// write to channel
ch <- x
// read from channel
x <- ch
// another way to read
x = <- ch
flag:
在 go 標準庫中提供了一個包:flag萤皂,方便進行命令行解析
定義 flags 有兩種方式
1)flag.Xxx(),其中 Xxx 可以是 Int匣椰、String裆熙,Bool 等;
返回一個相應類型的指針禽笑,如:
var ip = flag.Int("flagname", 1234, "help message for flagname")
第一個參數(shù) :flag名稱為flagname
第二個參數(shù) :flagname默認值為1234
第三個參數(shù) :flagname的提示信息
返回的ip是指針類型入录,
所以這種方式獲取ip的值應該fmt.Println(*ip)
2)flag.XxxVar(),將 flag 綁定到一個變量上佳镜,
如:
var flagValue int
flag.IntVar(&flagValue, "flagname", 1234, "help message for flagname")
第一個參數(shù) :接收flagname的實際值的
第二個參數(shù) :flag名稱為flagname
第三個參數(shù) :flagname默認值為1234
第四個參數(shù) :flagname的提示信息
這種方式獲取ip的值fmt.Println(ip)就可以了:
select:
select的用法與switch非常類似僚稿,由select開始一個新的選擇塊,每個選擇條件由case語句來描述蟀伸。每個case語句里必須是一個IO操作蚀同,確切的說,應該是一個面向channel的IO操作啊掏。
在執(zhí)行select語句的時候蠢络,運行時系統(tǒng)會自上而下地判斷每個case中的發(fā)送或接收操作是否可以被立即執(zhí)行(立即執(zhí)行:意思是當前Goroutine不會因此操作而被阻塞)。
函數(shù)和方法:
方法是包含了接收者的函數(shù)迟蜜。
函數(shù)的格式是固定的:func+函數(shù)名+ 參數(shù) + 返回值(可選) + 函數(shù)體
方法:func (variable_name variable_data_type) function_name() [return_type]{
? ?/* 函數(shù)體*/
}
defer后面的函數(shù)在defer語句所在的函數(shù)執(zhí)行結(jié)束的時候會被調(diào)用
有兩個常見的defer語句應用場景是:
1)file對象打開后的自動關閉? (在打開輸入文件輸出文件后刹孔,不管后面的代碼流程如何影響,這兩個文件能夠被自動關閉娜睛。)
func CopyFile(dstName, srcName string) (written int64, err error) {
? ? src, err := os.Open(srcName)
? ? if err != nil {
? ? ? ? return
? ? }
? ? defer src.Close()
? ? dst, err := os.Create(dstName)
? ? if err != nil {
? ? ? ? return
? ? }
? ? defer dst.Close()
? ? // other codes
? ? return io.Copy(dst, src)
}
2)mutex對象鎖住后的自動釋放(確保mu鎖能夠在函數(shù)foo退出之后自動釋放髓霞。)
func foo(...) {
? ? mu.Lock()
? ? defer mu.Unlock()
? ? // code logic
}
匿名函數(shù)的類似于下面這樣子:
func main() {
? ?func(message string) { //聲明匿名函數(shù)并執(zhí)行
? ? ? ?println(message)
? ?}("hello world!")
}
并不需要函數(shù)名,最后的小括號才是真正的調(diào)用畦戒,小括號里面?zhèn)鲄⒎娇猓丝梢杂糜趃oroutine以外還可以用于defer聲明
傳統(tǒng)散列:
當節(jié)點數(shù)變化時,絕大多數(shù)鍵需要重新分配障斋,傳統(tǒng)散列表的鍵對應的節(jié)點由其散列值對節(jié)點總數(shù)取膜決定薪捍。
一致性散列(散列環(huán)):一致性散列的實現(xiàn)方式可以被看成一個環(huán)。一致性散列可以極大地減少需要重新映射地鍵的數(shù)量配喳。
節(jié)點ID和key一樣需要進行散列計算酪穿,決定自己在環(huán)上的位置。計算散列值的散列函數(shù)由算法決定晴裹,不受節(jié)點總數(shù)變化的影響被济。
兩個相鄰節(jié)點的散列值決定一個半開半閉區(qū)間的范圍,落在這個范圍內(nèi)的鍵由閉節(jié)點處理涧团。新增或刪除節(jié)點的影響范圍僅限于該節(jié)點跟相鄰節(jié)點形成的區(qū)間只磷。
一致性散列還有一個比較重要的概念——虛擬節(jié)點经磅,它讓我們的負載分散得更均勻。
客戶端(瀏覽器算一種吧)的pipelining钮追,數(shù)據(jù)庫的批量寫入
通過基于數(shù)據(jù)庫來擴大緩存的容量(內(nèi)存大小有限预厌,基于磁盤的數(shù)據(jù)庫容量更大)