Go gc
時下流行的語言大都是運行在虛擬機上,如:Java 和 Scala 使用的 JVM,C# 和 VB.NET 使用的 .NET CLR。而go同樣通過虛擬機,採用標記-清除回收器管理內存,儘管虛擬機的性能已經有了很大的提升,但任何使用 JIT 編譯器和腳本語言解釋器的編程語言(Ruby、Python、Perl 和 JavaScript)在 C 和 C++ 的絕對優勢下甚至都無法在性能上望其項背
函數
func functionName(parameter_list) (return_value_list) { … }
parameter_list 的形式爲 (param1 type1, param2 type2, …)
return_value_list 的形式爲 (ret1 type1, ret2 type2, …)
只有當某個函數需要被外部包調用的時候才使用大寫字母開頭,並遵循 Pascal 命名法;類內部調用均首字母小寫
特殊函數
- 每個源文件都只能包含一個 init 函數。初始化總是以單線程執行,並且按照包的依賴關係順序執行。
- 如果當前包是 main 包,則定義 main 函數。package main表示一個可獨立執行的程序,每個 Go 應用程序都包含一個名爲 main 的包。包名都應該使用小寫字母
- 變參函數
func F1(s ...string) {
F2(s...) F3(s)
}
- defer 類似java finally 作用,它一般用於釋放某些已分配的資源
func function1() {
fmt.Printf("In function1 at the top\n")
defer function2()
fmt.Printf("In function1 at the bottom!\n")
}
- go 內置函數
- 函數作爲參數
函數可以作爲其它函數的參數進行傳遞,然後在其它函數內調用執行
func main() {
callback(1, Add)
}
func Add(a, b int) {
fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}
//函數func作爲參數傳入callback 方法
func callback(y int, f func(int, int)) {
f(y, 2) // this becomes Add(1, 2)
}
類型
基本類型,如:int、float、bool、string;
結構化的(複合的),如:struct、array、slice、map、channel;複合,go不存在繼承
只描述類型的行爲的,如:interface。
int 和 uint 在 32 位操作系統上,它們均使用 32 位(4 個字節),在 64 位操作系統上,它們均使用 64 位(8 個字節)
Go 語言中沒有 float和double 類型。只有 float32 和 float64。
類型轉換:
Go 語言不存在隱式類型轉換,因此所有的轉換都必須顯式說明,就像調用一個函數一樣。注意:
valueOfTypeB = typeB(valueOfTypeA)
小範圍轉大範圍ok,反之,丟失精度。只能在定義正確的情況下轉換成功,例如從一個取值範圍較小的類型轉換到一個取值範圍較大的類型(例如將 int16 轉換爲 int32)。當從一個取值範圍較大的轉換到取值範圍較小的類型時(例如將 int32 轉換爲 int16 或將 float32 轉換爲 int),會發生精度丟失(截斷)的情況。當編譯器捕捉到非法的類型轉換時會引發編譯時錯誤,否則將引發運行時錯誤。
字符串 string
string 工具類:strings 包和strconv包
strconv 與字符串相關的類型轉換都是通過 strconv 包實現的
strconv.Itoa(i int) string //數字轉string
strconv.Atoi(s string) (i int, err error) //string 轉int
strconv.ParseFloat(s string, bitSize int) //string 轉float64
變量
所有像 int、float、bool 和 string 這些基本類型都屬於值類型,使用這些類型的變量直接指向存在內存中的值
一個引用類型的變量 r1 存儲的是 r1 的值所在的內存地址(數字),或內存地址中第一個字所在的位置。當使用賦值語句 r2 = r1 時,只有引用(地址)被複制
如果 r1 的值被改變了,那麼這個值的所有引用都會指向被修改後的內容,在這個例子中,r2 也會受到影響。
被引用的變量會存儲在堆中,以便進行垃圾回收,且比棧擁有更大的內存空間。
空白標識符 _
_ 用於表示拋棄值,如值 5 在:_, b = 5, 7 中被拋棄。用於你並不需要使用從一個函數得到的所有返回值,import也同樣。
time包
time.Now()
t.Day()、t.Minute() //等等來獲取時間的一部分
time.After 或者 time.Ticker 定時執行
time.Sleep(Duration d) //可以實現對某個進程(實質上是 goroutine)時長爲 d 的暫停
結構
- if-else 結構
- switch 結構
- select 結構,用於 channel 的選擇(第 14.4 節)
- for (range) 結構 break continue
switch result := calculate() {
case result < 0:
...
case result > 0:
...
default: // 0
}
for i := 0; i < 5; i++ {
fmt.Printf("This is the %d iteration\n", i)
}
for index, value := range str {
...
}
regexp 包
pattern := "[0-9]+.[0-9]+" //正則
ok, _ := regexp.Match(pattern, []byte(searchIn))
//MatchString
sync併發包
當不同線程要使用同一個變量時,經常會出現一個問題:無法預知變量被不同線程修改的順序!(資源競爭)
在 Go 語言中這種鎖的機制是通過 sync 包來實現的,sync 來源於 "synchronized" 一詞,這意味着線程將有序的對同一變量進行訪問。
sync.Mutex 是一個互斥鎖 ,假設 info是一個需要上鎖的放在共享內存中的變量
import "sync"
type Info struct {
sync sync.Mutex
// ... other fields, e.g.: Str string
}
//update更新info結構
func Update(info *Info) {
info.sync.Lock()
// critical section:
info.Str = // new value
// end critical section
info.sync.Unlock()
}
sync.RWMutex 鎖 :讀寫鎖,多線程同時讀,只能一個線程進行寫。寫法與mutex一樣。
sync包中還有一個方便的 Once 類型變量的方法 once.Do(call),這個方法確保被調用函數只能被調用一次,使用如下:
once := sync.Once{}
once.Do(func() {
doInit()
})
對於簡單多線程操作下,可以使用sync包解決。但如果這種方式導致程序明顯變慢或者引起其他問題,我們要重新思考來通過 goroutines 和 channels 來解決問題,這是在 Go 語言中所提倡用來實現併發的技術。