Go語言中的標識符必須以字母(Unicode字母,PHP/JS能夠用中文做爲變量名)下劃線開頭。大寫字母跟小寫字母是不一樣的:Hello和hello是兩個不一樣的名字。
Go中有25個關鍵字:golang
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
若是一個名字是在函數內容定義,那麼它的做用域就在函數內容,若是在函數外部定義,那麼將在當前包的全部文件中均可以訪問。名字的開頭字母的大小寫決定了名字在包外的可見性。若是一個名字是大寫字母開頭,那麼它能夠被外部的包訪問,例如fmt包的Printf函數。數組
// 當前程序的包名 package main // 導入其餘的包 import "fmt" // 一次導入多個包 import ( "io" "os" ) // 常量的定義 const PI = 3.14 // 全局變量的聲明與賦值,該變量在整個package中使用 var name = "go" // 通常類型聲明 type newType int // 結構的聲明 type go struct{} // 接口的聲明 type golang interface{} // 由main函數做爲程序入口啓動 func main() { fmt.Println("Hello World!") }
Go語言中使用大小寫來決定該常量、變量、類型、接口、結構或函數是否能夠被外部包所調用: 根據約定,函數名首字母小寫即爲private(外部不能夠調用),大寫爲public緩存
// var 變量名稱 變量類型 = 值 var num int = 1
var num1,num2 int = 1, 2
var (
num1 int = 1 num2 int = 2 )
Go的整數類型一共有10個
其中計算架構相關的整數類型有兩個: 有符號的整數類型 int, 無符號的整數類型 uint。
在不一樣計算架構的計算機上,它們體現的寬度(存儲某個類型的值所須要的空間)是不同的。空間的單位能夠是bit也能夠是字節byte。
安全
除了這兩個計算架構相關的整數類型以外,還有8個能夠顯式表達自身寬度的整數類型:
數據結構
若是以8進製爲變量num賦值:架構
num = 039 // 用"0"做爲前綴以代表這是8進製表示法
若是以16進製爲變量num賦值:併發
num = 0x39
浮點數類型有兩個:float32/float64 浮點數類型的值通常由整數部分、小數點"."和小數部分組成。另一種表示方法是在其中加入指數部分。指數部分由"E"或"e"以及帶正負號的10進制整數表示。例:3.9E-2表示浮點數0.039。3.9E+1表示浮點數39。
有時候浮點數類型值也能夠被簡化。好比39.0能夠被簡化爲39。0.039能夠被簡化爲.039。 在Go中浮點數的相關部分只能由10進製表示法表示。app
複數類型有兩個:complex64和complex128。實際上,complex64類型的值會由兩個float32類型的值分別表示複數的實數部分和虛數部分。而complex128類型的值會由兩個float64類型的值表示複數的實數部分和虛數部分。
負數類型的值通常由浮點數表示的實數部分、加號"+"、浮點數表示的虛數部分以及小寫字母"i"組成,好比3.9E+1 + 9.99E-2i。函數
byte與rune都屬於別名類型。byte是uint8的別名類型,而rune是int32的別名類型。
一個rune的類型值便可表示一個Unicode字符。一個Unicode代碼點一般由"U+"和一個以十六進制表示法表示的整數表示,例如英文字母'A'的Unicode代碼點爲"U+0041"。
rune類型的值須要由單引號"'"包裹,不過咱們還能夠用另外幾種方式表示: ui
另外在rune類型值的表示中支持幾種特殊的字符序列,即:轉義符。以下圖:
字符串的表示法有兩種,即:原生表示法和解釋型表示法。原生表示法,需用用反引號"`"把字符序列包起來,若是用解釋型表示法,則須要用雙引號"""包裹字符序列。
var str1 string = "str" var str1 string = `str`
兩者的區別是,前者表示的是所見即所得的(除了回車符)。後者所表示的值中轉義符會起做用。字符串值是不可變的,若是咱們建立了一個此類型的值,就不可能再對它自己作任何修改。
一個數組是能夠容納若干相同類型的元素的容器。數組的長度是固定的。以下聲明一個數組類型:
type MyNumbers [3]int
類型聲明語句由關鍵字type、類型名稱和類型字面量組成
上面這條類型聲明語句其實是爲數組類型[3]int聲明瞭一個別名類型。這使得咱們能夠把MyNumbers看成數組類型[3]int來使用。
咱們表示這樣一個數組類型的值的時候。應該把該類型的類型字面量寫在最左邊,而後用花括號包裹該值包含的若干元素,各元素之間以(英文半角)逗號分割,即:
[3]int{1,2,3}
如今咱們把這個數組字面量賦給一個名爲numbers的變量:
var numbers = [3]int{1,2,3}
這是一條變量聲明語句,它在聲明變量的同時爲該變量賦值
另外一種方式是在其中的類型字面量中省略表明其長度的數組,例:
var numbers = [...]int{1,2,3}
能夠用以下方式訪問該變量中的任何一個元素。例:
numbers[0] numbers[1] numbers[2]
若是要修改數組值中的某一個元素值,能夠:
numbers[1] = 4
能夠用以下方式獲取數組長度:
var length = len(numbers)
若是一個數組沒有賦值,則它的默認值爲[length]type{0,0,0...}
切片(slice)與數組同樣也是能夠若干相同類型元素的容器。與數組不一樣的是切片類型的長度不肯定。每一個切片值都會將數組做爲其底層數據結構。表示切片類型的字面量如:
[]int
或者是:
[]string
切片類型的聲明能夠這樣:
type MySlice []int
對切片值的表示也與數組值類似
[]int{1,2,3}
操做數組值的方法一樣適用於切片值。還有一種操做數組的方式叫作「切片」,實施切片操做的方式就是切片表達式。例:
var number3 = [5]int{1,2,3,4,5} var slice1 = numbers3[1:4]
上例中切片表達式numbers3[1:4]的結果爲[]int{2,3,4}很明顯被切下的部分不包含元素上界索引指向的元素。實際上slice1這個切片值的底層數組正是number3的值。
咱們也能夠在切片值上實施切片操做:
var slice2 = slice1[1:3]
除了長度切片值以及數組值還有另一個屬性--容量。數組的容量老是等於其長度,而切片值的容量每每與其長度不一樣。以下圖:
如圖所示,一個切片值的容量即爲它的第一個元素值在其底層數組中的索引值與該數組長度的差值的絕對值。可使用cap()內建函數獲取數組、切片、通道類型的值的容量:
var capacity2 int = cap(slice2)
切片類型屬於引用類型,它的零值即爲nil,即空值。若是咱們只聲明瞭一個切片類型而不爲它賦值,則它的默認值:nil。
有些時候咱們能夠在方括號中放入第三個正整數。以下圖所示:
numbers3[1:4:4]
第三個正整數爲容量上界索引,它意義在於能夠把做爲結果的切片值的容量設置的更小。它能夠限制咱們經過這個切片值對其底層數組中的更多元素的訪問。上節中numbers3和slice的賦值語句以下:
var numbers3 = [5]int{1,2,3,4,5} var slice1 = numbers3[1:4]
這時,變量slice1的值是[]int{2,3,4}。可是咱們能夠經過以下操做將其長度延展與其容量相同:
slice1 = slice1[:cap(slice1)]
經過此操做,變量slice1的值變爲了[]int{2,3,4,5},且其長度和容量均爲4。如今number3的值中的索引值在(1,5)範圍內的元素都被體如今了slice1的值中。這是以number3的值是slice1的值的底層數組爲前提的。這意味着咱們能夠垂手可得地經過切片訪問其底層數組中對應索引值更大的更多元素。若是咱們編寫的函數返回了這樣一個切片值,那麼獲得它的程序極可能會經過這種技巧訪問到本不該該暴露給它的元素。
若是咱們在切片中加入了第三個索引(即容量上限索引),如:
var slice1 = numbers3[1:4:4]
那麼在此以後,咱們將沒法經過slice1訪問到number3的值中的第五個元素。
雖然切片值在上述方面受到了其容量的限制。可是咱們能夠經過另一種手段對其進行不受限制的擴展。這須要用到內建函數append。append會對切片值進行擴展並返回一個新的切片值,使用方法以下:
slice1 = append(slice1, 6, 7)
經過上述操做,slice1的值變爲了[]int{2,3,4,6,7}。一旦擴展操做超出了被操做的切片值的容量,那麼該切片的底層數組就會被替換 最後一種操做切片的方式是「複製」。該操做的實施方法是調用copy函數。該函數接收兩個類型相同的切片值做爲參數,並把第二個參數值中的元素複製到第一個參數值中的相應位置(索引值相同)上。這裏有兩點須要注意:
例:
var slice4 = []int{0,0,0,0,0,0} copy(slice4, slice1)
經過上述複製操做,slice4會變成[]int{2,3,4,6,7,0,0}。
Go語言的字典(Map)類型是一個哈希表的實現。字典類型的字面量以下:
map[K]T
其中,"K"爲鍵的類型,而"T"則表明元素(值)的類型。若是咱們描述一個鍵類型爲int,值類型爲string的字典類型的話:
map[int]string
字典的鍵類型必須是可比較的,不然會引發錯誤,即鍵不能是切片、字典、函數類型
字典值的字面量表示法實際上與數組的切片的字面量表示法很類似。最左邊仍然是類型字面量,右邊緊挨着由花括號包裹且有英文逗號分隔的鍵值對。每一個鍵值對的鍵和值之間由冒號分隔。以字典類型map[int]string爲例。他的值的字面量能夠是這樣的:
map[int]string{1:"a",2:"b"m,3:"c"}
咱們能夠把這個值賦給一個變量
mm := map[int]string{1:"a",2:"b",3:"c"}
可用索引表達式取出字典中的值:
b := mm[2]
能夠用索引表達式賦值:
mm[2] = b + "2"
這樣mm中鍵爲2的值變爲了"b2"。能夠用以下方式向字典中添加一個鍵值對:
mm[4] = ""
對於字典值來講,若是指定鍵沒有對應的值則默認爲該類型的空值。因此mm[5]會返回一個""。可是這樣的話咱們就不知道mm[5]究竟是""仍是mm[5]沒有這個值。因此go提供了另一種寫法:
e, ok := mm[5]
針對字典的索引表達式能夠有兩個求職結果,第二個求職結果是bool類型的。它用於代表字典值中是否存在指定的鍵值對。 從字典中刪除鍵值對的方法很是簡單,僅僅是調用內建函數delete:
delete(mm, 4)
不管mm中是否存在以4爲鍵的鍵值對,delete都刪除。 字典類型屬於引用類型,它的零值即爲nil
通道(Channel)是Go語言中一種很是獨特的數據結構。它可用於在不一樣Goroutine之間傳遞類型化的數據。而且是併發安全的。相比之下,以前幾種數據類型都不是併發安全的。
Goroutine能夠被看做是承載可被併發執行的代碼塊的載體。它們由Go語言的運行時系統調度,並依託操做系統線程(又稱內核線程)來併發地執行其中的代碼塊。
通道類型的表示方法很簡單,僅由兩部分組成:
chan T
在這個類型字面量中,左邊是表明通道類型的關鍵字chan,而右邊則是一個可變的部分,即表明該通道類型容許傳遞的數據的類型(或稱通道的元素類型)。
與其餘的數據類型不一樣,咱們沒法表示一個通道類型的值,所以,咱們沒法用字面量來爲通道類型的變量賦值。只能經過調用內建函數make來達到目的。make參數可接受兩個參數,第一個參數是表明了將被初始化的值的類型的字面量(例: chan int),而第二個參數則是值的長度,例如,若咱們想要初始化一個長度爲5且元素類型爲int的通道值,則須要這樣寫:
make(chan int, 5)
make函數也能夠被用來初始化切片類型或字典類型的值。
暫存在通道值中的數據是先進先出。下面,咱們聲明一個通道類型的變量,併爲其賦值:
ch1 := make(chan string, 5)
這樣一來,咱們就可使用接受操做符<-向通道值發送數據了。固然,也可使用它從通道值接收數據,例如,若是咱們要向通道ch1 發送字符串"value1",那麼應該這樣作:
ch1 <- "value1"
若是咱們從ch1那裏接收字符串,則要這樣:
<- ch1
咱們能夠把接受到字符串賦給一個變量,如:
value := <- ch1
與針對字典值的索引表達式同樣,針對通道值的接受操做也能夠有第二個結果值:
value, ok := <- ch1
這裏的ok的值是bool類型的。它表明了通道值的狀態,true表明通道值有效,而false則表明通道值已無效(或稱已關閉),更深層次的緣由是,若是在接受操做進行以前或過程當中通道值被關閉了,則接收操做會當即結束並返回一個該通道值的元素類型的零值。
能夠經過函數close來關閉通道:
close(ch1)
對通道值的重複關閉會引起運行時異常,會使程序崩潰。在通道值有效的前提下,針對它的發送操做會在通道值已滿(其中緩存的數據的個數已等於它的長度)時被阻塞。而向一個已被關閉的通道值發送數據會引起運行時異常。針對有效通道值的接收操做會在它已經爲空時被阻塞。通道類型屬於引用類型,它的零值爲nil。
上一節中的通道實際上只是Go中的通道的一種。是帶緩衝的通道,或者簡稱爲緩衝通道。
通道有緩衝和非緩衝之分,緩衝通道中能夠緩存N個數據,咱們在初始化一個通道值的時候必須指定這個N,**相對的非緩衝通道不會緩存任何數據,發送方在向通道發送數據的時候會當即被阻塞。直到有一個接收方已從該通道中接收了這條數據。**非緩衝的通道值的初始化方法以下:
make(chan int, 0)
除了上述分類方法,咱們還能夠以數據在通道中的傳輸方向爲依據來劃分通道。默認狀況下,通道都是雙向的,即雙向通訊。若是數據只能在通道中單向傳輸,那麼該通道被稱做單向通道。咱們在初始化一個通道值的時候不能指定爲單向。可是在編寫類型聲明的時候能夠:
type Receiver <- chan int
類型Receiver表明了一個只從中接收數據的單向通道類型,這樣的通道也被稱爲接收通道。在關鍵字chan左邊的接收操做符<-表示了數據的流向。相對應的,若是咱們想聲明一個發送通道類型,那麼應該這樣:
type Sender char <- int
此次<-被放在了chan的右邊,而且「箭頭」直指「通道」。咱們能夠把一個雙向通道賦予上述類型的變量,就像這樣:
var myChannel = make(chan int, 3) var sender Sender = myChannel var receiver Receiver = myChannel
可是反過來是不行的:
var myChannel1 chan int = sender
單向通道的做用主要是約束程序對通道值的使用方式,好比,咱們調用一函數時給予它一個發送通道做爲參數,以此來約束它只能向該通道發送數據。又好比,一個函數將一個接受通道做爲結果返回,以此來約束調用該函數的代碼只能從這個通道中接收數據。