Go 語言進階——函數-變量-類型-併發 基礎

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 語言中所提倡用來實現併發的技術。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章