1. 程式人生 > >go語言程式初學

go語言程式初學

建立一個用於編寫Go程式的工作目錄go-examples,其絕對路徑為/home/go-examples.開始編寫我們的第一個Go程式。

一、在go-work下建立一個檔案hello.go

複製程式碼程式碼如下:
//hello.go   
package main

import "fmt"//實現格式化的I/O  
 
/*Printf someting*/  
func main(){   
       fmt.Printf("Hello,GO!\n")   
}

我們來分析下這個程式:

1、程式中的第2行這個是必須的。所有的Go檔案以package <something>開頭,對於獨立執行的執行檔案必須是package main;

2、第4行說需要將”fmt”包加入main。不是main的其他包都被稱為庫,其他許多程式語言有著類似的概念。

3、第1行和第4行中的//和/*---*/都是註釋

4、package main 必須首先出現,緊跟著是import。在Go中,package 總是首先出現,然後是import,然後是其他所有內容。當Go 程式在執行的時候,首先呼叫的函式是main.main(),這是從C 中繼承而來。這裡定義了這個函式;

5、第8行呼叫了來自於fmt包的函式列印字串到螢幕

二、編譯和執行程式碼

編譯該原始檔並執行生成的可執行檔案

複製程式碼程式碼如下:
[root@localhost go-wrok]# go build hello.go   
[root@localhost go-work]# ls   
hello hello.go   
[root@localhost go-work]# ./hello   
Hello,GO!  

通過go build加上要編譯的Go原始檔名,我們即可得到一個可執行檔案,預設情況下這個檔案的名字為原始檔名字去掉.go字尾。當然我們也可以通過-o選項來指定其他名字:

複製程式碼程式碼如下:
[root@localhost go-examples]# go build -o firstgo hello.go   
[root@localhost go-examples]# ls   
firstgo hello.go  

如果我們在go-examples目錄下直接執行go build命令,後面不帶檔名,我們將得到一個與目錄名同名的可執行檔案:

複製程式碼程式碼如下:
[root@localhost go-examples]# go build   
[root@localhost go-examples]# ls   
go-examples hello.go  

三、程式入口點(entry point)和包(package)

Go保持了與C家族語言一致的風格:即目標為可執行程式的Go原始碼中務必要有一個名為main的函式,該函式即為可執行程式的入口點。除此之外 Go還增加了一個約束:作為入口點的main函式必須在名為main的package中。正如上面hellogo.go原始檔中的那樣,在原始碼第 一行就聲明瞭該檔案所歸屬的package為main。

Go去除了標頭檔案的概念,而借鑑了很多主流語言都採用的package的原始碼組織方式。package是個邏輯概念,與檔案沒有一一對應的關係。 如果多個原始檔都在開頭宣告自己屬於某個名為foo的包,那這些原始檔中的程式碼在邏輯上都歸屬於包foo(這些檔案最好在同一個目錄下,至少目前 的Go版本還無法支援不同目錄下的原始檔歸屬於同一個包)。

我們看到hellogo.go中import一個名為fmt的包,並利用該包內的Printf函式輸出"Hello, Go!"。直覺告訴我們fmt包似乎是一個標準庫中的包。沒錯,fmt包提供了格式化文字輸出以及讀取格式化輸入的相關函式,與C中的printf或 scanf等類似。我們通過import語句將fmt包匯入我們的原始檔後就可以使用該fmt包匯出(export)的功能函數了(比如 Printf)。

在C中,我們通過static來標識區域性函式還是全域性函式。而在Go中,包中的函式是否可以被外部呼叫,要看該函式名的首母是否為大寫。這是一種 Go語言固化的約定:首母大寫的函式被認為是匯出的函式,可以被包之外的程式碼呼叫;而小寫字母開頭的函式則僅能在包內使用。在例子中你也看到了 fmt包的Printf函式其首母就是大寫的。

四、GOPATH

把上面的hellogo.go稍作改造,拆分成兩個檔案:main.go和hello.go

複製程式碼程式碼如下:
//hello.go   
package hello   
  
import "fmt"  
  
func Hello(who string){   
     fmt.Printf("Hello,%s!\n", who)   
}  
複製程式碼程式碼如下:
//main.go   
package main   
  
import "hello"  
  
func main(){   
     hello.Hello("GO")   
}

用go build編譯main.go 結果如下

複製程式碼程式碼如下:
[root@localhost go-examples]# go build main.go   
main.go:4:8: import "hello": cannot find package  

編譯器居然提示無法找到hello這個package,而hello.go中明明定義了package hello了。這是怎麼回事呢?原來go compiler搜尋package的方式與我們常規理解的有不同,Go在這方面也有一套約定,這裡面涉及到一個重要的環境變數:GOPATH。我們可以使用go help gopath來檢視一下有關gopath的manual。

Go compiler的package搜尋順序是這樣的,以搜尋hello這個package為例:

* 首先,Go compiler會在GO安裝目錄(GOROOT,這裡是/home/go/)下查詢是否有src/pkg/hello相關包原始碼;如果沒有則繼續;

* 如果export GOPATH=PATH1:PAHT2,則Go compiler會依次查詢是否存在PATH1/src/hello、PATH2/src/hello;配置在GOPATH中的PATH1和PATH2被稱作workplace;

* 如果在上述幾個位置均無法找到hello這個package,則提示出錯。

在本例子中,我們尚未設定過GOPATH環境變數,也沒有建立類似PATH1/src/hello這樣的路徑,因此Go compiler顯然無法找到hello這個package了。我們來設定一下GOPATH變數並建立相關目錄:

複製程式碼程式碼如下:
[root@localhost go-examples]# export GOPATH=/home/go-examples/   
[root@localhost go-examples]# mkdir src/hello -p   
[root@localhost go-examples]# mv hello.go src/hello/   
[root@localhost go-examples]# go build main.go   
[root@localhost go-examples]# ls   
main main.go src   
[root@localhost go-examples]# ./main   
Hello,GO!  

五、Go install

將main.go移到src/main中,這樣這個demo project顯得更加合理,所有原始碼均在src下:

複製程式碼程式碼如下:
[root@localhost go-examples]# cd src/   
[root@localhost src]# ls   
hello main.go  

Go提供了install命令,與build命令相比,install命令在編譯原始碼後還會將可執行檔案或庫檔案安裝到約定的目錄下。我們以main目錄為例:
複製程式碼程式碼如下:
[root@localhost src]# cd main/   
[root@localhost main]# go install  

install命令執行後,我們發現main目錄下沒有任何變化,原先build時產生的main可執行檔案也不見了蹤影。別急,Go install也有一套自己的約定:

* go install(在src/DIR下)編譯出的可執行檔案以其所在目錄名(DIR)命名

* go install將可執行檔案安裝到與src同級別的bin目錄下,bin目錄由go install自動建立

* go install將可執行檔案依賴的各種package編譯後,放在與src同級別的pkg目錄下

現在我們來看看bin目錄:

複製程式碼程式碼如下:
[root@localhost go-examples]# ls   
bin pkg src   
[root@localhost go-examples]# ls bin/   
main  

的確出現一個bin目錄,並且剛剛編譯的程式main在bin下面。

hello.go編譯後並非可執行程式,在編譯main的同時,由於main依賴hello package,因此hello也被關聯編譯了。這與單獨在hello目錄下執行install的結果是一樣的,我們試試:

複製程式碼程式碼如下:
[root@localhost src]# cd hello/   
[root@localhost hello]# go install   
[root@localhost hello]# ls /home/go-examples/   
bin pkg src  

在我們的workspace(go-examples目錄)下出現了一個pkg目錄,pkg目錄下是一個名為linux_386的子目錄,其下面有一個文 件:hello.a。這就是我們install的結果。hello.go被編譯為hello.a並安裝到pkg/linux_386目錄下了。

.a這個字尾名讓我們想起了靜態共享庫,但這裡的.a卻是Go獨有的檔案格式,與傳統的靜態共享庫並不相容。但Go語言的設計者使用這個字尾名似乎是希望 這個.a檔案也承擔起Go語言中"靜態共享庫"的角色。我們不妨來試試,看看這個hello.a是否可以被Go compiler當作"靜態共享庫"來對待。我們移除src中的hello目錄,然後在main目錄下執行go build:

複製程式碼程式碼如下:
[root@localhost main]# go build   
main.go:4:8: import "hello": cannot find package  

Go編譯器提示無法找到hello這個包,可見目前版本的Go編譯器似乎不理pkg下的.a檔案。http://code.google.com/p/go/issues/detail?id=2775 這個issue也印證了這一點,不過後續Go版本很可能會支援連結.a檔案。畢竟我們在使用第三方package的時候,很可能無法得到其原始碼,並且在每個專案中都儲存一份第三方包的原始碼也十分不利於專案原始碼的後期維護。