1、程序結構程序員
Go程序結構和C系程序(C/C++/JAVA等)一致,基本語句被組織成函數用於隔離和複用,函數組成源文件和包。Go程序存儲在一個或多個.go文件中,每一個文件都已pakage開頭,表面當前文件屬於哪一個包;package語句後面是import語句,用於包含其餘包以便於使用其餘包中的元素;以後是包級別的類型、變量、常量、函數聲明,聲明不用區分先後順序。編程
例:json
pakage main
import 「fmt」
var name = 「tony」 func main(){ //函數、控制語句的前半大括號必須和函數名在同一行 fmt.Printf(「name = %s」,name) }
注意:變量聲明區別於C的是類型後知,例如var name string;數組
特色:對比C,go有以下常見特色:多線程
1)、變量聲明還能夠經過返回值完成,例如name := getname(),稱之爲短聲明;併發
2)、函數返回值能夠有多個,例如ret1,ret2 = getret(),ret1和ret2將得到getret函數返回的兩個參數;同時賦值表達式也能夠多重賦值,如x,y=10,20 ;app
3)、賦值多了一種「:=」,這種用法用於定義一個類型是返回值類型的變量,同時該變量的值爲返回值。是一種方便程序員的特性;編程語言
4)、新類型聲明用type關鍵字;例如 type mytype string,那麼mytype能夠等價於string;函數
5)、包初始化時從包級別變量開始,這些變量按照聲明順序初始化,對於多個文件的包,初始化順序是傳給編譯器的文件順序,每一個包,甚至每一個文件均可以定義一個init函數,在裏邊能夠自定義初始化一些內容,這個函數會在初始化階段自動調用,且這個函數不是給用戶調用的。優化
2、數據類型
go的數據類型包括基礎類型、聚合類型、引用類型、接口類型四大類。
基礎類型包括數字、字符串和布爾型;聚合類型有數組和結構體;引用類型包括slice、指針、map、函數、通道;接口類型即「接口」類型。
1)、基礎類型使用上參考C系語言,差異不大,不過go對這些基礎類型作了各類優化,好比內置複數類型、提供常量生成器、方便操做字符串等。
2)、數組和結構體長度都是固定的,slice和map的長度是能夠動態增加的;
①、slice表示一個擁有相同元素的可變長序列,一般寫做[]T ;slice有三個屬性,指針、長度、容量,在長度變長的過程當中,容量會適時的增長以適應元素增長;len和cap用來返回slice的長度和容量;
②、map,即鍵值對類型,這種類型在平常開發者很經常使用,因此go內置了;map的類型是map[K]v ;map要求k必須是相同類型,V是相同類型,但K和V的類型能夠不一樣;而且要求K的值必須是能夠經過==操做符來進行比較的數據類型,目的是能夠檢索某一個K是否已經存在。空map表示爲map[k]v{} 。
③、結構體相似於C系語言的結構體;
④、go標準庫支持操做json、xml等經常使用格式標記語言。
3、函數
go函數聲明以下格式:
func name(para-list) (ret-list){ body }
常規操做相似於C系語言,因此再也不多加描述。
特性:延遲函數調用
用defer關鍵字後跟函數調用,這種格式的函數調用將會在當前函數執行流程結束後執行;不論是正常return仍是程序產生異常都會在最終調用defer語句;defer語句能夠在須要的地方屢次調用,defer語句常常適用於成對操做中,如文件打開關閉,這時不管文件操做成功與否最後確定是要關閉文件的,因此這一特性是頗有用的。
resp.err := http.Get(url) if err != nil{ return err } defer resp.Body.Close()
4、方法
方法在本質上等同於函數,但它是對於面向對象編程而言的;go是一種支持大多數面向對象編程特性的編程語言,因此也存在繼承、複用等。
方法聲明和普通函數相比函數前面多了個參數,以下:
func (p class) name(para-list) (ret-list){ body }
多出的這個類參數意圖是把當前函數綁定到這個參數對應的類型上。和C系語言不一樣的是這個參數顯示指定了特定類型實例p,而不是用隱性的this、self、that等;這樣的好處是由用戶本身選擇當前方法的接收者p 。
以上的p也能夠是指針類型,這樣能夠避免參數複製。
合法的方法調用僅如下三種狀況:
//如下三種狀況的 前置條件 func (p Point) Distance(q Point) float64 { body } func (p *Point) ScaleBy (q Point) float64 { body } var pptr *Point
1)、實參接收者和形參接收者類型相同,即同是T或*T
Point{1,2}.Distance(q) //Point
pptr.ScaleBy(q) //*Point
2)、實參接收者是T而形參接收者是*T,編譯器會隱式獲取地址;
p. ScaleBy(q) //
3)、實參接收者是*T而形參接收者是T,編譯器會隱式轉換。
pptr.Distance(q)
Notice: nil是個合法接收者
5、封裝
go只有一種方式控制命名的可見性:定義的時候首字母大寫的標識符是能夠從包中導出的,小寫的標識符只能在包中使用。
6、接口
接口類型是對其餘類型行爲的歸納和抽象。接口類型是一種抽象類型,它提供的僅僅是一些方法。舉個例子:
type ControllerInterface interface { Init(ct *context.Context, controllerName, actionName string, app interface{}) Get() Post() Delete() Put() Head() Patch() Options() }
一個接口類型定義了一組方法,若是一個具體類型要實現這個接口,那麼他必須實現接口類型中提供的全部方法。
若是一個類型實現了一個接口所要求的的全部方法,那麼這個類型實現了這個接口;接口的賦值規則很簡單,僅當一個表達式實現了一個接口時這個表達式才能賦值給該接口。
package io type Reader interface{ Read() } type ReadWriter interface{ Read() Write() } type Writer interface{ Write() }
依據以上前置條件如下賦值狀況爲:
var w io.Writer
w =os.Stdout //能夠 *osFile 有write方法
w = time.Secound //不能夠 未實現write方法
因此,接口能夠當作普通變量看待,申請變量時它是nil,僅當賦值特定實現它要求的方法的類型後它將得到這個類型的具體方法,以後用這個變量完成特定的操做。
類型斷言:
形如X.(T)的操做稱之爲類型斷言,其中X是一個接口類型表達式,T是一個類型;類型斷言會檢查做爲操做數的動態類型是否知足指定的斷言類型;做用結果分爲兩種可能:
1)、T是一個具體類型,從它的操做數中把具體類型的值提取出來;
var w io.Writer
w = os.Stdout
f := w.(*os.File) // f = os.Stuout
2)、 T是一個接口類型,從一個接口類型向另外一個更寬鬆的接口類型轉化(方法增多)
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // 成功,rw將會變成包含Read和Write的接口
7、併發編程
go支持兩種類型的併發編程風格,goroutine+channel風格(CSP)和共享內存多線程風格,go編程中第一種比較常見,由於使用很簡單方便。
go裏每個併發執行的活動稱爲goroutine;在函數調用或者表達式前加關鍵字go便可達成建立新的goroutine去執行表達式任務的目的;因此比起傳統的多線程編程要簡單得多。
固然程序執行的時候建立不少goroutine達成併發執行的目的了,但這些goroutine之間若是不能有效溝通那程序的功能將很大程度上受限,因此咱們須要這些goroutine之間通訊的機制,此處引入channel(通道)