golang小程式實驗(四)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

1. golang的函數類型轉換

一個go playground的例子,首先定義一個func類型的別名A,然後定義了A的一個方法。再定義一個函數,此函數的參數與傳回值與A相同(這樣才能顯式轉換)。在main中把此函數顯式轉換為A類型,這樣它就可以調用A的方法了。

package mainimport "fmt"type A func(int, int)func (f A)Serve() {fmt.Println("serve2")}func serve(int,int) {fmt.Println("serve1")}func main() {a := A(serve)a(1,2)a.Serve()}

2. golang的http包處理流程

func HelloServer(w http.ResponseWriter, req *http.Request) {    io.WriteString(w, "hello, world!\n")} func main() {    http.HandleFunc("/hello", HelloServer)    err := http.ListenAndServe(":12345", nil)    if err != nil {        log.Fatal("ListenAndServe: ", err)    } }

首先調用Http.HandleFunc

按順序做了幾件事:

1 調用了DefaultServerMux的HandleFunc

2 調用了DefaultServerMux的Handle

3 往DefaultServeMux的map[string]muxEntry中增加對應的handler和路由規則

其次調用http.ListenAndServe(":12345", nil)

按順序做了幾件事情:

1 執行個體化Server

2 調用Server的ListenAndServe()

3 調用net.Listen("tcp", addr)監聽連接埠

4 啟動一個for迴圈,在迴圈體中Accept請求

5 對每個請求執行個體化一個Conn,並且開啟一個goroutine為這個請求進行服務go c.serve()

6 讀取每個請求的內容w, err := c.readRequest()

7 判斷header是否為空白,如果沒有設定handler(這個例子就沒有設定handler),handler就設定為DefaultServeMux

8 調用handler的ServeHttp

9 在這個例子中,下面就進入到DefaultServerMux.ServeHttp

10 根據request選擇handler,並且進入到這個handler的ServeHTTP

       mux.handler(r).ServeHTTP(w, r)

11 選擇handler:

    A 判斷是否有路由能滿足這個request(迴圈遍曆ServerMux的muxEntry)

    B 如果有路由滿足,調用這個路由handler的ServeHttp

    C 如果沒有路由滿足,調用NotFoundHandler的ServeHttp

可以看一下這篇文章的介紹:http://www.cnblogs.com/yjf512/archive/2012/08/22/2650873.html

3. golang的閉包一例

package mainimport "fmt"func adder() func(int) int {     sum := 0     return func(x int) int {          sum += x          return sum     }}func main() {     pos, neg := adder(), adder()     for i := 0; i < 10; i++ {          fmt.Println(               pos(i),               neg(-2*i),          )     }}
對於以上代碼的正確結果,需要理解閉包中的全域和局部變數,sum是全域變數,x是局部變數,這樣就不會錯了。

運行結果:

0 01 -23 -66 -1210 -2015 -3021 -4228 -5636 -7245 -90

4. 擷取golang的各種路徑

使用者當前所在路徑:

os.Getwd()

執行程式檔案相對路徑:

file, _ := exec.LookPath(os.Args[0])

package mainimport(        "os"        "log"        "os/exec"        "path")func main() {        file, _ := os.Getwd()        log.Println("current path:", file)        file, _ = exec.LookPath(os.Args[0])        log.Println("exec path:", file)        dir,_ := path.Split(file)        log.Println("exec folder relative path:", dir)        os.Chdir(dir)        wd, _ := os.Getwd()        log.Println("exec folder absolute path:", wd)}

可執行檔我放在/home/lm/handcode/test

我執行的路徑是/home/lm/

[lm@openstack ~]$ handcode/test2013/02/06 11:09:07 current path: /home/lm2013/02/06 11:09:07 exec path: handcode/test2013/02/06 11:09:07 exec folder relative path: handcode/2013/02/06 11:09:07 exec folder absolute path: /home/lm/handcode

5. golang的Error()

可以為自訂對象定義自己的Error()、String()方法,從而輸出指定資訊:

package mainimport ("fmt""math")type ErrNegativeSqrt float64func (e ErrNegativeSqrt) Error() string {return "cannot Sqrt negative number:" + fmt.Sprint(float64(e))}func Sqrt(f float64) (float64, error) {if f < 0 {return 0, ErrNegativeSqrt(f)}z := float64(1)for {y := z - (z*z-f)/(2*z)if math.Abs(y-z) < 1e-10 {return y, nil}z = y}return z, nil}func main() {fmt.Println(Sqrt(2))fmt.Println(Sqrt(-2))}
當f<0時把f顯式轉換成 ErrNegativeSqrt類型,傳入到error,就會調用自訂的ErrNegativeSqrt的Error()方法。

6. golang匯入自己的package

以前寫的go程式都是在main包中,即使有多個go檔案,其開頭都是package main,所以它們都屬於main包。今天實驗了一下其它自定一包的匯入:定義了fsnotify.go和fsnotify_linux.go,這兩個檔案屬於package fsnotify;定義main.go,屬於package main。main.go會調用fsnotify包中的方法,那麼怎樣匯入fsnotify包呢?

在fsnotify包沒有被正確匯入時,會提示如下錯誤:

[root@localhost src]# go build main.gomain.go:5:5: cannot find package "fsnotify" in any of:/software/go/src/pkg/fsnotify (from $GOROOT)/software/fsnotify/src/fsnotify (from $GOPATH)
也就是說在main.go中的import "fsnotify"首先根據$GOROOT找,如果找不到再根據$GOPATH找,還找不到的話就提示以上錯誤。先執行go env看一下go對應的環境變數:
[root@localhost software]# go envGOARCH="amd64"GOBIN=""GOCHAR="6"GOEXE=""GOHOSTARCH="amd64"GOHOSTOS="linux"GOOS="linux"GOPATH="/software/fsnotify"GORACE=""GOROOT="/software/go"GOTOOLDIR="/software/go/pkg/tool/linux_amd64"TERM="dumb"CC="gcc"GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread"CXX="g++"CGO_ENABLED="1"

所以正確的做法是在$GOROOT/src/pkg下建立一個與自訂包名相同的檔案夾,然後把相應檔案放到這個檔案夾下;或者在$GOPATH/src下建立一個與自訂包名相同的檔案夾,把相應檔案放進去,就OK了。一般情況下都是使用第二種做法。

$GOPATH可以定義多個路徑,與$PATH的道理一樣,可以在/root/.bashrc中這樣定義$GOPATH:

GOPATH=/software/fsnotify:/software/tmpexport GOPATH

然後把之前的fsnotify檔案夾mv到/software/tmp/src下,go build main.go依然成功,以上兩點得到驗證。

7. golang的項目目錄結構

一般的,一個go項目在$GOPATH下會有如下3個目錄:

——bin——pkg——src
其中,bin存放編譯後的可執行檔;pkg存放編譯後的包檔案;src存放項目源檔案。一般bin和pkg目錄可以不建立,go命令會自動建立(如 go install),只需要建立src目錄即可。對於pkg目錄,pkg中的檔案是Go編譯產生的,而不是手動放進去的。(一般檔案尾碼.a)對於src目錄,用來存放源檔案,Go中源檔案以包(package)的形式組織。通常,建立一個包就在src目錄中建立一個檔案夾。

比如建立一個名為test的go項目,初始目錄如下:

test/|——install|——src
install內容如下:
#!/usr/bin/env bashif [ ! -f install ]; thenecho 'install must be run within its container folder' 1>&2exit 1fiCURDIR=`pwd`OLDGOPATH="$GOPATH"export GOPATH="$CURDIR"gofmt -w srcgo install testexport GOPATH="$OLDGOPATH"echo 'finished'

之所以加上這個install,是不用配置GOPATH(避免新增一個GO項目就要往GOPATH中增加一個路徑)

接下來,增加一個包:config和一個main程式。目錄結構如下:

test|-- install`-- src    |-- config    |   `-- config.go    `-- test        `-- main.go

注意config.go中的package名稱最好和目錄config一致,而檔案名稱可以隨便。main.go表示main包,檔案名稱建議為main.go。(註:不一致時,產生的.a檔案名稱和目錄名一致,這樣,在import 時,應該是目錄名,而引用包時,需要包名。例如:目錄為myconfig,包名為config,則生產的靜態包檔案是:myconfig.a,引用該包:import “myconfig”,使用包中成員:config.LoadConfig())

config.go代碼:

package configfunc LoadConfig() {}
main.go代碼:
package mainimport ("config""fmt")func main() {config.LoadConfig()fmt.Println("Hello, GO!")}

在項目根目錄執行./install

這時候的目錄結構為:

test|-- bin|   `-- test|-- install|-- pkg|   `-- linux_amd64|       `-- config.a`-- src    |-- config    |   `-- config.go    `-- test        `-- main.go

其中config.a是包config編譯後產生的;bin/test是產生的二進位檔案

這個時候可以執行:bin/test了。會輸出:Hello, GO!

包可以多層目錄,比如:net/http包,表示源檔案在src/net/http目錄下面,不過源檔案中的包名是最後一個目錄的名字,如http

而在import包時,必須完整的路徑,如:import “net/http”。

go build與go install的區別:

go build:在臨時目錄下建立包編譯後的二進位檔案,該命令不會將二進位檔案安裝到 bin、pkg目錄;go build後面直接接需要編譯的檔案名稱。

go install:和 go build 參數相同,唯一的區別在於將編譯結果拷貝到 bin、pkg目錄中;go install需要建立一個與項目目錄同名的子目錄,然後把main.go放進去;go install接項目目錄名。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.