當前位置:
首頁 > 最新 > 【教你編程】go語言簡介

【教你編程】go語言簡介

golang 簡介


golang 簡介概述開發環境搭建安裝 go 編譯器設置環境變數go 語言編輯器第三方庫的安裝和 GOPATH 的目錄結構離線安裝一些無法訪問的庫go 文檔語法簡介變數申明遍曆數組,mapgo 的結構體go 的 interface 類型package 和 init 函數啟動一個 go routine並發時的通訊 go channeldefer關鍵字內存管理一些注意的點代碼實例xml 文件的解析和生成json 文件的解析和生成結構體上綁定方法正則表達式的匹配一行代碼實現 http 文件伺服器

概述


很方便的處理各種格式化文件,xml,json 等

很方便的處理各種網路操作,例如 TCP 連接,UDP 連接,監聽埠

很方便的處理 http 相關的請求,http 服務端

模板語言功能齊全,包括 http 頁面和文本的模板,也就是我司的動態替換

很方便的進行並發,go {}

簡化版的面對對象,通過定義一個結構體,然後在結構體上綁定方法來實現

常見的數據結構,鏈表,map,hash 等都有內置實現

常見的加密演算法,例如 MD5,AES,RC4 等也都有內置實現

正則表達式,字元串操作,等都有內置的實現

開發環境搭建


GOARCH="amd64"

GOBIN=""

GOCACHE="/home/test/.cache/go-build"

GOEXE=""

GOHOSTARCH="amd64"

GOHOSTOS="linux"

GOOS="linux"

GOPATH="/home/test/go"

GORACE=""

GOROOT="/usr/lib/go-1.10.3"

GOTMPDIR=""

GOTOOLDIR="/usr/lib/go-1.10.3/pkg/tool/linux_amd64"

GCCGO="gccgo"

CC="gcc"

CXX="g++"

CGO_ENABLED="1"

CGO_CFLAGS="-g -O2"

CGO_CPPFLAGS=""

CGO_CXXFLAGS="-g -O2"

CGO_FFLAGS="-g -O2"

CGO_LDFLAGS="-g -O2"

PKG_CONFIG="pkg-config"

GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build812137494=/tmp/go-build -gno-record-gcc-switches"

目前用過的 go 語言編輯器,最好用的是 liteide ,其他的也有支持 golang 的編輯器,例如 vscode 等liteide 支持自動提示,自動格式化代碼等,推薦使用 liteide下載地址:http://liteide.org/cn/https://github.com/visualfc/liteide/releases/下載之後,同樣是解壓到一個目錄,然後運行該目錄裡面的 liteide 即可,為了方便可以將其添加到任務欄。打開 liteide 之後,編輯一個 hello.go ,使用快捷鍵即可執行編譯,使用快捷鍵即可編譯並運行,如果成功列印出了,則說明安裝成功了。

packagemain

import(

"log"

)

funcmain() {

log.Printf("hello world!")

return

}


目前 go 還沒有庫的管理,安裝第三方庫都是直接在網上下載的,比較常用的都是在上下載,安裝庫的命令是,例如當需要更新一個庫時go get 命令會自動從https://github.com/astaxie/beego的地址去下載源碼並安裝如果沒有網路怎麼辦呢?下面介紹 GOPATH 目錄結構,之後就知道如何離線安裝第三方庫了GOPATH 是 go 的庫目錄,類似於 C 語言的 lib 目錄,下面是一個 GOPATH 目錄的例子

gopath

src

github.com

astaxie

beego

bin

pkg其中 bin 目錄是存放一些可執行文件的,當在一個項目中執行,則會將編譯好的可執行文件放到目錄下;pkg 是一個編譯時的中間目錄,該目錄下會有不同操作系統不同架構的文件夾,平時也用不到,不用去管;src 目錄就是源碼目錄,所有的 go package 都需要有源碼,而 go get 命令下載源碼也是放到這個路徑的。源碼路徑是和 url 的目錄結構相對應的,例如一個第三方庫,其目錄結構也有三級,,所以離線安裝的話,就可以直接訪問https://github.com/astaxie/beego,將源碼包下載下來,再將其按照對應的目錄放置即可。


當有些第三方庫地址無法訪問(有些是牆外才能訪問),這時候有一個方法https://golangtc.com/download/package這個網站專門做了一個下載的頁面,用來應對這種情況,詳細地可以參看這個網址的頁面下載下來之後按照上面的步驟離線安裝即可


官網有一個 go 標準庫的文檔,https://golang.google.cn/pkg/安裝了 go 之後,本地也可以啟動一個 http 服務,來查看 go 文檔,和官網的是一致的,區別在於,本地安裝了第三方庫,也會在頁面中顯示出來。啟動方法

godoc-http"127.0.0.1:6666"

語法簡介


variint=

i:=

var(

j:=

k:=1

)

vardataMyData

data:=&MyData{}

vardbmap[string]string

varstrs[]string


varstrs[]string

forindex,val:=rangestrs{

log.Printf("index:%s, val:%s",index,val)

}

vardbmap[string]string

forkey,val:=rangedb{

log.Printf("key:%s,val:%s",k,v)

}這裡需要注意的是,遍歷的時候,range 關鍵字是會新分配內存的,例如上面的代碼中 val 的值是新分配的,二不是數組或者 map 裡面的內容,所以通過 val 去修改是不會生效的,想要修改必須用下標去引用。


go 的結構體有點像是簡化版的 class

typePersonstruct{

Namestring// public

Sexstring

ageint

secrectstring// private

}

func(this*Person)Eat()error{

returnnil

}

func(this*Person)Sleep() (string,error) {

return"private",nil

}

func(this*Person)Say(msgstring)error{

fmt.Sprintf(msg)

returnnil

}

typeCoderstruct{

Person

Langstring// program language

}

func(this*Coder)WriteCode()error{

returnnil

}

func(this*Coder)FixBug()error{

returnnil

}

func(this*Coder)Eat()error{

this.Person.Eat()

returnnil

}

typeTesterstruct{

Person

Toolsstring// test tools

}

func(this*Tester)Test()error{

returnnil

}


golang 官網上對於 interface 的介紹:https://golang.google.cn/ref/spec#Interface_types

An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.可以看到 interface 是一個函數集合類型,可以保存任何擁有這些函數集合的超集的類型,未賦值的 interface 為nil。

typeHumaninterface{

Eat()error

Sleep()error

Say(msgstring)error

}

typeManstruct{

Person

Moneyint

}

func(this*Man)Pay(costint)error{

this.Money-=cost

ifthis.Money

returnerrors.New("no money")

}

returnnil

}

typeWomanstruct{

Person

Bagstring

}

func(this*Woman)Shopping() (int,error) {

cost:=100

returncost,nil

}

varjackMan

varroseWoman

funcMeet(a,bHuman)error{

varerrerror

varcostint

a.Say("hello!")

b.Say("Nice to meet you too!")

a.Eat()

b.Eat()

ifv,ok:=b.(Woman);ok{

cost,err=v.Shopping()

}

ifv,ok:=a.(Man);ok{

err=v.Pay(cost)

}

a.Say("Goodbye!")

b.Say("See you!")

returnnil

}

funcmain() {

Meet(jack,rose)

}


go 中所有的代碼都是以 package 的形式存在,同一個程序中 main package 只有一個,而其他 package 可以有很多個,通過 import 來引用其他 package,引用方法是通過路徑,而路徑會在 GOPATH 裡面尋找對應的代碼。

packagemain

import(

"log"

"hello/hello"

"github.com/astaxie/beego"

_"github.com/go-sql-driver/mysql"

)

funcinit() {

// do something

}

funcmain() {

log.Printf("started")

hello.Print("hello")

beego.Run()

return

}所有的 package 有一個 init 函數會默認調用,而且是在 import 階段就會調用,例如上面的代碼中,在 main 函數進入之前,就會執行 init 函數,以及引用的三個庫的 init 函數,最終才進入 main 函數的流程。上述代碼中 mysql 的 package 前面有一個下劃線,表示僅僅執行該 package 中的 init 函數,而不引用其中的方法或者類型。在目錄下有一個 hello 的 package

packagehello

import(

"fmt"

)

var(

prefixstring="say:"

)

funcinit() {

Print("here is init for hello")

}

funcPrint(msgstring)error{

fmt.Sprintf(prefix+"msg")

returnnil

}這樣可以對代碼進行功能拆分,變成一個一個的 package ,從而實現模塊化。


go 的線程叫協程

gofunc() {

log.Printf("begin")

// sleep

log.Printf("end")

}()go 關鍵字後面跟上函數,就會啟動一個 go routine 去執行。


在並發時,需要進行通訊,可以使用 channel 類型,中文叫信道。

packagemain

import(

"fmt"

)

funcmain() {

varfinishchanint=make(chanint)

gofunc() {

fori:=;i

fmt.Printf("%d ",i)

}

finish

}()

}這裡 chan 就是一個 channel 類型,其中信道的操作是一個比較難理解的點,這裡有一個關鍵字,,當 chan 在左邊時,右邊就是要往信道發送的內容。當 chan 在右邊時,表示監聽信道,直到有內容過來,此時左邊是沒內容的信道 chan 還分為無緩衝的信道,帶緩衝的信道,例如上面的代碼中

varfinishchanint=make(chanint)這就是一個無緩衝的信道,當發送給信道的內容沒有被接受時,發送端是會阻塞的,直到內容被信道接收,例如上面的例子,如果主線程一直不處理子線程發送的 0 ,則子線程也會阻塞。當我們如下定義時

varfinishchanint=make(chanint,100)這就是一個有100個緩衝區的信道,此時往信道裡面發消息的時候不會阻塞,除非信道緩衝區滿了。需要注意的是,chan 也是有死鎖的情況的,當所有的 runtine 都進入等待狀態,則會死鎖,所以寫代碼的時候要注意。其他 chan 相關的知識,可以自行查找資料了解更多。


defer 後面跟一個函數,通常是在函數返回之前執行,例如

funcmain() {

fd,err:=os.Open("1.txt")

iferr!=nil{

returnerr

}

deferfd.Close()

// xxxx

return

}上述代碼打開了一個文件,以前 C 語言的習慣是,在文件使用完之後執行 Close,在 go 裡面也可以繼續這樣做,但是使用了 defer 關鍵字之後,就可以保證資源的打開和關閉在同一個地方,提高了代碼的可讀性,也避免了打開了忘記關閉資源的情況。上述的關閉文件句柄函數會在執行 return 時隱式的調用。defer 也可以像 go 關鍵字一樣寫

deferfunc() {

// do something

}()


go 語言和 java 一樣是有垃圾回收的,通常內存分配之後不需要執行 free / delete 來手動釋放,分配內存有兩個關鍵字 new / make。new 關鍵字和我們常理解的是一致的,它接受一個類型參數,分配內存,然後返回該類型的指針。

vari*string

i=new(string)

*i="hello"new 出來的類型會被初始化為初始值,int 為 0,string 為 "",其他引用類型為 nilmake 關鍵字專門用來分配數組(也叫切片)、map、chan 這幾種引用類型,返回的是這幾種類型本身,不是指針。

varfinishchanint=make(chanint,100)

varstrs[]string=make([]string,)

maps:=make(map[string]string,)


go 語言的大括弧不允許換行,必須在上一行代碼的末尾,否則會報錯

行尾不能有分號

import 了一個庫卻不使用,會報錯

代碼實例


packagemain

import(

"encoding/xml"

"log"

)

typeMyDatastruct{

XMLNamexml.Name`xml:"root"`

Namestring`xml:"name"`

Statusstring`xml:"status"`

}

funcEncodeXml() {

vardataMyData

data.Name="test1"

data.Status="stopped"

out,err:=xml.Marshal(data)

iferr!=nil{

log.Fatal(err)

}

log.Printf(string(out))

}

funcDecodeXml() {

vardataMyData

varxmlstrstring=`test2running`

err:=xml.Unmarshal([]byte(xmlstr),&data)

iferr!=nil{

log.Fatal(err)

}

log.Printf("%+v",data)

}

funcmain() {

EncodeXml()

DecodeXml()

}


packagemain

import(

"encoding/json"

"log"

)

typeMyDatastruct{

Namestring`json:"name"`

Statusstring`json:"status"`

}

funcEncodeJson() {

vardataMyData

data.Name="test3"

data.Status="running"

out,err:=json.Marshal(data)

iferr!=nil{

log.Fatal(err)

}

log.Printf(string(out))

}

funcDecodeJson() {

vardataMyData

varjsonstrstring=`{"name":"test4","status":"crashed"}`

err:=json.Unmarshal([]byte(jsonstr),&data)

iferr!=nil{

log.Fatal(err)

}

log.Printf("%+v",data)

}

funcmain() {

EncodeJson()

DecodeJson()

}


packagemain

import(

"encoding/json"

"log"

)

typeMyDatastruct{

Namestring`json:"name"`

Statusstring`json:"status"`

}

func(this*MyData)Encode() (string,error) {

out,err:=json.Marshal(this)

iferr!=nil{

return"",err

}

returnstring(out),nil

}

func(this*MyData)Decode(strstring)error{

err:=json.Unmarshal([]byte(str),this)

iferr!=nil{

returnerr

}

returnnil

}

func(this*MyData)Debug() {

log.Printf("debug: name=%s, status=%s",this.Name,this.Status)

return

}

funcmain() {

vardataMyData

varjsonstrstring=`{"name":"test5","status":"running"}`

err:=data.Decode(jsonstr)

iferr!=nil{

log.Fatal(err)

}

data.Debug()

data.Name="test6"

data.Status="stopped"

out,err:=data.Encode()

iferr!=nil{

log.Fatal(err)

}

log.Printf(out)

}


packagemain

import(

"log"

"regexp"

)

funcmain() {

line:="11.22.33|44.55.66"

pcrestr:="(\d+).(\d+).(\d+)"

re:=regexp.MustCompile(pcrestr)

results:=re.FindAllStringSubmatch(line,-1)

for_,matched:=rangeresults{

log.Printf("%s, %s, %s
",matched[1],matched[2],matched[3])

}

return

}


packagemain

import(

"log"

"net/http"

)

funcmain() {

log.Fatal(http.ListenAndServe(":8080",http.FileServer(http.Dir("/tmp/test"))))

}


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 孤獨的飯桶 的精彩文章:

TAG:孤獨的飯桶 |