一、第一個go程式
package mainimport ( "fmt")func main(){ fmt.Println("hello world")}
對於代碼的解釋
如果是為了將代碼編譯成一個可執行程式,那麼package必須是main
如果是為了將代碼編譯成庫,那麼package則沒有限制
go中所有的代碼都應該隸屬一個包
fmt 是go的一個系統庫
fmt.println()則可以列印輸出
如果想要運行程式:go run 程式名
在一個可執行程式只有一個main函數
關於注釋
單行注釋://
多行注釋:/* */ 二、go語言初識
關於定義一個變數
var 變數名 變數類型
變數名 = 值
這裡需要注意:go語言中定義的變數必須被用到,否則會報錯
同時定義變數和賦值可以一步完成通過: 變數名 := 值
定義一個函數
如果我們要定義一個函數,我們先看下面求和的例子:
func add(a int,b int) int { var sum int sum = a + b return sum}
這裡我們需要知道,下面這種格式是被嚴格要求的沒包括第一行的大括弧不能放到下一行
func 函數名(參數1 參數1類型,參數2 參數2類型) 傳回值類型 {
} 三、golang語言特性
記憶體回收
記憶體自動回收,不需要開發人員管理記憶體
開發人員專註業務實現
只需要new分配記憶體,不需要釋放
天然高並發 從語言曾元支援並發,非常簡單 goroute,輕量級線程,建立成千上萬goroute成為可能 基於CSP模型實現
關於高並發的一個簡單示範:
package mainimport ( "fmt" "time")func test_print(a int){ fmt.Println(a)}func main(){ for i:= 0;i < 100; i ++ { go test_print(i) } time.Sleep(time.Second)}
在實現高並發的時候只需要在調用的函數前面加上go,就表示開啟了並發
如果在for迴圈的外面不加上time.Sleep(time.Second),就會發現會少列印了,這是因為當主程式運行完之後,並不會等待線程,所以程式直接終止
channel管道
類似linux中的pipe
多個goroute之間通過channel進行通訊
支援任何類型
package mainimport ( "fmt")func test_pipe(){ pipe := make(chan int,3) pipe <- 1 pipe <- 2 pipe <- 3 fmt.Println(len(pipe))}func main(){ test_pipe()}
上述代碼的解釋:
pipe := make(chan int,3) 這裡是定義一個管道pipe,go是強型別語言,所以這裡聲明一個管道變數pipe需要通過有三個參數,chan表示是管道,int表示管道類型,3表示管道容量
通過len(pipe)可以查看管道的的長度
如果想要從管道裡擷取資料
t1 :=<- pipe 這個寫法等同於
var t1 int
t1 = <- pipe
fmt.Println(t1)
管道遵循的原則是先進先出,所以第一個擷取的值是1
小結:如果想要給管道放入值:定義的管道pipe < - 要存入的內容
如果想要從管道中擷取值:變數名 =<- 定義的管道pipe
這裡強調一下go中package包的概念,一個包裡的變數,在這個包裡是都可以訪問,但是在包之外也是有許可權限制是否可以訪問到,如果一個變數在一個包裡是大寫的,在其他包裡就可以訪問到,如果是小寫其他包裡則訪問不到。類似其他語言中的public和private
多傳回值
一個函數可以返回多個值
package mainimport "fmt"func calc(a int,b int) (int,int ){ sum := a + b avg := sum / 2 return sum,avg}func main(){ sum,avg := calc(100,200) fmt.Println(sum,avg)}
關於需要傳入多個參數的時候是用括弧括起來單個的情況下一般不用括弧括起來,直接int,而這裡是返回兩個則需要 (int,int)表示返回兩個整數類型值
如果有多個傳回值,但是我只想返回一個值,是通過底線方式實現,則上述代碼改為:
func main(){ sum,_ := calc(100,200) fmt.Println(sum)}
四、包的概念 和python一樣,把相同功能的代碼放到一個目錄,稱之為包 包可以被其他包引用 main包是用來產生可執行檔,每個程式只有一個main包 包的主要用途是提高代碼的課複用性
關於main包中的main函數,go程式經過編譯之後,運行該程式,會將編譯好的二進位檔案載入到記憶體中,會首先調用main函數,所以main函數是程式的入口函數,即必須有package main
關於包,是我們可以把一些常用的功能封裝到包中,這個時候包中的每個go檔案的開頭則不需要package main,而是package 自訂名字 這個自訂名字是根據這個包的功能進行命名
go源碼按package進行組織,並且package要放到非注釋的第一行
一個程式只有一個main包,一個包中只能有一個main函數,不能重複定義
main函數是程式的執行入口
沒有被引用的變數,編譯的時候會報錯
go的目錄規範
這裡舉一個簡單的例子:如果我們在建立一個go_project目錄,通常在這個目錄下我們會建立如下目錄
src 存放不同的項目代碼
bin 存放編譯後的可執行程式
vender 存放引用的第三方庫
pgk 存放靜態庫
我們的go環境變數中的GOPATH一般會設定為:
(我這裡是路徑是/users/zhaofan/go_project)
export GOPATH=/users/zhaofan/go_project
go的編譯
如果我們寫好了go的代碼檔案,我們如果測試回合可以通過:
go run 快速執行go檔案
go build 編譯器,產生二進位檔案
go install 安裝可執行檔到bin目錄下
基本命令:
go test執行單元測試或壓力測試
go env 顯示go相關的環境變數
go fmt 格式化原始碼
我們通過下面例子理解這個編譯命令的使用:
例子一
我在/users/zhaofan/go_project/src/go_dev/day01/hello目錄下寫了一個hello程式
現在把這個hello程式進行編譯
我們在go_project目錄下執行的編譯命令,如果不指定編譯產生的檔案會直接將編譯檔案產生在目前的目錄即go_project目錄下
這裡需要解釋的是go build 後面的路徑go build go_dev/day01/hello
我們從目錄結構可以看出,go_dev的上一級目錄src目錄並沒有寫,這是因為go編譯的時候,會自動去GOPATH下的src目錄裡去找,所以這裡是不需要寫,同時編譯的路徑的最後我們唯寫到hello目錄而不是hello.go檔案
例子二
我們在/users/zhaofan/go_project/src/go_dev/day01/ 目錄下建立一個goroute目錄
並在goroute目錄下建立兩個go檔案,main.go和goroute.go檔案
main.go檔案的代碼為:
package mainimport ( "time")func main(){ for i := 0; i < 100; i++ { go test_goroute(i) } time.Sleep(time.Second)}
goroute.go檔案的代碼為:
package mainimport "fmt"func test_goroute(a int){ fmt.Println(a)}
這樣我們編譯的時候只需要在go_project目錄下執行:
go build go_dev/day01/goroute
這樣就會再go_project目錄下產生一個可執行檔goroute
例子3
還是在/users/zhaofan/go_project/src/go_dev/day01/下建立一個goroute_test目錄
在goroute_test目錄下建立calc目錄和main目錄
同時在calc下建立一個sum.go檔案,在main目錄下建立一個main.go檔案
su