GO語言入門

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

Google系統所使用的程式設計語言Go,近年來發展的越來越成熟、方便易用。現在,我們可以通過使用LiteIDE讓Go語言編程變得更加簡單。(註:按本文標題和結尾來看,本文應該只是一個系列中的第一部分。本部分著重介紹語言基礎,所以跟大標題可能有些出入。)

第一步 語言基礎

資料、類型、函數、控制

Go語言是一個很容易上手同時功能無比強大的程式設計語言。你可以將它看做是C的現代版,至於更多的東西,還有待你自己去發掘。Go語言有著清晰簡明的靜態文法結構,但它表現出來的確是一種動態效果。它還可以編譯成本地代碼,但卻像解釋性語言那樣去工作。

總的來說,Go語言是一門完全值得你去嘗試的語言,同時本文將告訴你一切你上手這門語言所需要知識。在第二部分,我們將重點分析Go語言是如何處理對象和並發的。

     !                   
       
正在載入...

安裝 

安裝和配置Go語言,你只需要下載合適的二進位檔案至正確的位置,再為Go工具定位那些檔案所在的目錄路徑就好了。 

如果你使用的是OSX或Windows作業系統,那麼你可以使用安裝包來完成這一些列工作。

在Windows下,我推薦MSI安裝包,這個安裝包雖然還在實驗中,但其實它的表現非常不錯,它能迅速地為你完成配置工作。 你需要的只是根據你的系統下載32位或64位安裝包然後在你的電腦上運行就好了。

安裝程式會預設在C:\Go目錄進行安裝。

你可以通過下面的小程式驗證環境是否搭建完成:

package main
import "fmt"
func main() {
 fmt.Printf("hello, world\n")
}

你可以使用記事本或其他文字編輯器編輯上面這段代碼,並將代碼儲存為hello.go檔案。然後開啟終端,輸入:

go run hello.go

接下來你就可以進行LiteIDE的安裝並嘗試運行程式了。

     

不管從什麼方面來說,LiteIDE並不是編寫Go程式的必備工具,你所需要的只是一個編輯器而已。這樣說的確沒錯,但是對於一個新人,一個好的IDE可以使他更容易上手一門語言,並迅速投入開發。

美中不足的是,LiteIDE沒有使用手冊。

你可以從下面的網址上下載tar或zip壓縮包

https://code.google.com/p/golangide/ 

下載完成後將其解壓至合適的目錄。如果你是用的是Windows,那你可能需要使用7z來解壓。

如此簡潔的安裝過程必然不會為你建立捷徑,因此你可能需要開啟...\liteide\bin然後找到liteide.exe並手動建立捷徑。

         

開啟LiteIDE後你會看到歡迎介面:

現在我們暫時無需理會這些組件,讓我們先從一個簡單的小程式開始。

在工具列上選擇File->New或直接在歡迎介面上點擊New按鈕,在彈出的對話方塊中選擇Go1 Command Project。LiteIDE將為你建立一個Go控制台工程,工程目錄放在C:/Go/src下。如果你為你的項目起名Hello,那你的代碼檔案將被放在 C:/Go/src/Hello下。

LiteIDE會預先為你在工程目錄下建立main.go和doc.go檔案。main.go檔案中包含以下內容:

// Hello project main.go
package main
import (
    "fmt"
)
func main() {
    fmt.Println("Hello World!")
}

你可以點擊工具列上藍色的編譯執行按鈕BR運行代碼。你可以在在Build菜單中的B和BR按鈕菜單中找到更多的關於編譯和執行代碼的命令。

如果你運行了你的程式,你可以在底部的編譯輸出(Build Output)視窗中看到程式運行結果。

如果程式沒有運行,那麼很有可能是你建立的工程類型不對或者檔案路徑錯誤。

LiteIDE中還有很多功能等待你去發掘,不過目前為止的這些已經足夠我們使用Go語言了。

         

變數和單一資料型別

Go語言套件含了你所期望的所有從uint8 到 float64的單一資料型別。

  • uint8  無符號8位 整型數(0 到 255)
  • uint16 無符號16位 整型數(0 到  65535)
  • uint32 無符號32位 整型數(0 到  4294967295)
  • uint64 無符號 64位 整型數(0 到   18446744073709551615)

  • int8  8位 整型數(-128 到  127)
  • int16  16位 整型數(-32768 到  32767)
  • int32 32位 整型數(-2147483648到  2147483647)
  • int64 64位 整型數(-9223372036854775808到  9223372036854775807)

  • float32  IEEE-754 32位 浮點數
  • float64  IEEE-754 64位 浮點數

  • complex64  複數 32位實數+32位虛數
  • complex128  複數 64位實數+64位虛數

  • byte uint8的別稱
  • rune  int32的別稱

最大的驚喜就在於,Go語言支援複數類型的資料:

var z complex64
z = 1.0 + 2.0i
fmt.Println(z)

如果你想知道rune是什麼,那麼當你知道rune被用來儲存一個Unicode字元的時候,這個問題也就應該迎刃而解了吧。換句話說,rune在Go語言中等價於字元(char)類型。

當然你也可以使用uint、int卷二uintptr這些依賴於系統類別型(32位或64位)的整數類型。

另外一個新穎的地方,當你定義一個變數的時候,你變數的後面對其類型進行定義,而不是在前面。

當你在定義中初始化了變數,你無需對變數指定資料類型。如果在定義的時候未初始化,則變數將會被賦予0值:

var i=0
var x,y float32=1.0,2.0

和數字類型一樣,Boolean 類型也有相似的特徵。

編譯器會完成相應的工作。

一個使用Go語言定義和初始設定變數的簡單例子:

x,y:=1,2

你也可以定義和使用常量。

             

資料結構

常用的資料結構有字串(strings),數組(arrays)和結構體(structs),以及另一位頗受歡迎的成員map。

字串是Unicode編碼,其值不能修改,而其他方面和你想的差不多。

s="Hello"

可以使用len函數擷取字串的長度,使用索引操作符[0]可以訪問字串中的字元。Go語言中的字串類型相當簡陋,但使用stirng package可以實作類別似其他語言字串的所有功能。

數組(arrays)以中括弧([])聲明,索引從零開始。例如:

var buff [32]byte
fmt.Println(buff[10])

多維陣列通過數組的數組實現,

var buff [32][32]byte
fmt.Println(buff[10][0])

數組(array)不是動態,不能動態分配大小。但可以使用切片(slice)實現同樣的效果。切片包含數組(array)的一部分,可以動態變更大小。

結構體(structs)與其他語言類似,如下:

func main() {

    type point struct {
      x, y int
    }
    var p = point{10, 10}
    fmt.Println(p.x)
}

上例聲明了新的結構體類型,包括兩個成員x和y。在main函數中建立並初始化了該結構體類型的執行個體(instance)。Go語言通常不使用術語“執行個體(instance)”,而更喜歡使用術語“值(value)”,所以你是建立了該類型的一個值(value)。

結構體定義中可以嵌套結構體作為成員。初始化器(initializer){10,10}是結構體literal(譯註:literal可以理解為立即數,見維基)。在結構體literal中也可以使用成員名例如{X:10}。

這是我們首次介紹Go類型,關於這個話題之後還有更多內容。

最後一個資料類型是Map,等價於其他語言中的hash map,關聯陣列(associative array)或者字典(dictionary)。

給定鍵的類型以及值的類型就能建立Map。如果從來沒有使用過關聯陣列,那就把它想象成一個數組,數組的值不是通過索引訪問,而是通過通用類型的鍵訪問。例如。:

var m = make( map[string]int) 
m["mike"] = 10
m["lucy"] = 30
fmt.Println(m["lucy"])

顯示結果是30.

make函數是能夠基於Type(類型)建立Value(值)(譯註:可以理解為執行個體)的兩個函數之一,要詳細瞭解它,我們需要學習更多關於類型的內容。


 
正在載入...

Go語言的類型起到的作用與眾所周知的物件導向的設計語言(Java、C++)有很大的不同,它沒有所謂的層次劃分、沒有類的概念也不存在繼承。類型是可以被推斷出來的,如:Go使用鴨子類型。

你可以用一個立即數(literal )或指定的類型來定義一個類型變數,以達到類型重用的目的。

自訂類型是由一些小的資料類型整合而成的,如數組、結構體、指標、很熟、介面、片、map和channel。

定義類型的方法:

type 類型名 資料類型

例:

type myint int

定義myint為一個整數型別。如果你想建立一個擴充類型,重新定義之前聲明過的類型的資料類型也很常用,實現的函數和方法我們之後再講。

更為通常的做法,你可以使用某些資料類型組成你自訂的類型:

 type point struct {
    x, y int
}

這就是一個新的類型結構。

你也可以聲明數群組類型: 

type myarray [20]int

你可以在定義類型時使用自訂類型:

type point struct {
        x, y int    
}    
type arrayPoints [10]point

這就建立了一個point類型的數組。

你可以自行探索其他的類型定義方式。接下來我們要做的是理解Go能用這些類型完成什麼工作?

類型主要被用於下面兩個方面:

  • 類型檢測

  • 建立值

類型檢測很常見——你只能賦予你定義的變數與之相同類型的值。在編譯時間編譯器會依此對靜態類型進行檢查。

例:

var c myint    
c = "string"

上面的代碼編譯將不會通過。但下面的代碼:

var c myint    
c = 1

將會通過編譯。因為“c”和“1”都是整型資料。

  

類型所做的第二件事:在你用型別宣告變數時構造對應類型的變數。如:

var i int

var p point

但對於slice(片)、map和channel來說他們必須使用make函數建立對應類型的值。

var m = make( map[string]int) 

make函數是Go語言支援的兩個分配函數中的一個,另一個是new函數。make函數建立了一個指定類型的值,並把該值得指標返回給變數。在大多數地方,Go中的指標與C中的指標使用方法類似。

你可以使用*引用一個指標的值,也可以用&擷取值得地址。但是,Go和C的指標也存在差異,這種區別在於Go語言不存在指標計算。在Go語言中,指標存在的意義是讓你可以用引用的方式在函數之間傳遞參數。

如果你有一個類型T,那麼*T就是一個指向類型T的指標。

舉一個new函數的例子:

var add= new(int)

在這裡,new函數建立了一個整型變數並放回了它的地址存放在add中。變數add的類型為*int。

如果你寫出如下語句

fmt.Print(add)

那麼你將得到這個整型值得地址。那麼,為了列印這個整型變數的值,我們需要這樣書寫列印語句:

fmt.Print(*add)

就像之前提到過的那樣,你可以直接使用類型的值而無需給這個類型命名:

var p struct {
        x, y int
    }

如果你不需要重用這個類型,那麼這樣做也是可以的。

            

函數

Go不是一種基於類並且有階層的語言,也不使用通常的方式處理對象。如果你僅僅打算實現一個函數,那就不用考慮有關對象的內容。函數就是一個值(Values),是“一等對象“。

如下,聲明一個函數

var myFunc = func(a, b int) int {
    return a + b
}
可以指定參數類型和傳回值類型,如果指定了傳回值類型,則函數中必須有return語句。

函數值(value)被賦值給了變數myFunc。也可以按照通常的方式定義函數,這是變數myFunc就是函數的名稱。

func myFunc(a, b int) int {
    return a + b
}
無論那種方式,函數都可以使用下面的方式調用:

fmt.Println(myFunc(1, 2))

可以在return語句中返回多個值,並且可以在函數頭中指定傳回值的名稱。

例如:

func myFunc(a, b int) (sum int) {
    sum = a + b
    return
}
sum就是函數的傳回值。

返回多個值也很簡單:

func myFunc(a, b int) (int, int) {
    return a + b, a - b
}
必須全部接收函數的兩個傳回值:

   x,y := myFunc2(1, 4)
   fmt.Println(x,y)
其他語言中可以選擇只接收一個傳回值,但在Go語言中不可以。


傳值——指標

所有的形參都是以傳值的方式傳入,所以對形參做的任何改變都不會影響實參。例如:

func myFunc(a, b int) int {
    a = 1
    return a + b
}
函數中對形參a的指派陳述式,對實參沒有任何影響。就是說

x, y := 2, 3
var sum = myFunc(x, y)
fmt.Println(sum, x)
顯示結果是4和2。x的值沒有變化。

如果想要改變實參的值,就需要傳入指標(譯註:即傳地址或傳引用)作為參數。例如,變更函數定義如下:

func myFunc(a *int, b int) int {
    *a = 1
    return *a + b
}
參數a以指標的形式傳入,對a的指派陳述式改變a指向的變數。調用函數時,我們需要傳入變數的地址作為參數:

var sum = myFunc(&x, y)
fmt.Println(sum, x)
現在顯示結果是4和1,x的值變更了。

*和&操作符的用法對C程式員來說是非常熟悉的,這體現了Go語言較為初級的一面。有爭議說在現代語言中所有的參數都應該以傳引用的方式傳入。

如果函數定義中的參數是*int類型,而調用該函數時沒有使用&運算元,那麼在編譯階段類型檢查時就會報錯,而C語言沒有這個功能。

總之,Go語言的指標類型,可以作為實參傳遞給函數,但無法在資料上耍一些”聰明“的技巧。

      

範圍和閉包

你可以以嵌套的方式在函數中定義函數。在某塊代碼中定義的變數只會在該塊代碼地區和該代碼地區內的地區生效。這意味著你可以在函數之外定義全域變數,那麼所有的函數將都能使用這個變數。

例:

var a1 int = 1
func main() {
    fmt.Println(a1)
    var a2 int = 2
    var myFunc = func() int {
        return a2
    }
    fmt.Println(myFunc())
}

在這個例子中,a1是一個全域變數,可以被所有函數訪問。a2在main函數內定義,因此它可以被main函數和main中的myFunc函數訪問。

Go同樣支援閉包。如果你在一個函數中定義了另一個函數,那麼這個在內部的函數將能夠訪問外部函數的變數,即使外部函數已經終止運行。在外部函數停止後保持內建函式的唯一方法是將其作為一個傳回值返回給外部函數。

例: 

func myFunc() func() int {
    var a int = 1
    return func() int {
        return a
    }

在這裡,內建函式以func() int的方式返回給外部函數。函數和它的內容都是以類型的方式返回的。返回的函數將會返回外部函數定義的變數的值,這就是閉包的作用。

因此

myClosure := myFunc()
fmt.Println(myClosure())

輸出結果為 1.

每個閉包都有一份與自己綁定的變數副本,閉包不會實現不同函數副本之間的資料共用。


Go 控制

現在我們已經瞭解過了資料、類型和函數。接下來我們將討論另一個重要的問題:Go語言提供的控制語句。

實際上,Go語言只提供了很少的控制結構,它極大簡化了控制語句的使用。

Go語言是一種塊結構的程式設計語言,它使用"{}"將一組程式碼群組成塊。如果你一直在奇怪其他程式設計語言中經常使用的“;”去了哪裡,我可以很明確的告訴你,在Go中它依然存在,只是在編譯過程中它會自動為你加上“;”。如果你也在代碼末尾加上分號,那麼編譯器將會認為它們是不需要的字元,從而自動剔除這些分號。

for迴圈是Go語言中的唯一一種迴圈。for迴圈可以被用來建立條件迴圈和枚舉迴圈。

for迴圈具有下面這種形式:

for 條件
    操作
}

需要注意的是,你無需將迴圈的條件置於一對大括弧“{}”中。迴圈將會在不滿足條件時終止。迴圈將會在每次執行迴圈體前檢查條件是否滿足,因此迴圈體可以被執行0次或很多次,類似於while迴圈。

例:

i:=0

for a<10 { 
 fmt.print(a)
 a=a+1
}

你可以通過使用for true {" 或者 "for {" 來建立一個不會終止的迴圈。

枚舉迴圈與其他類似C的語言基本相同:

for 運算式1 ; 條件 ; 運算式3{
  操作
}

運算式1會在迴圈開始前執行一次,運算式3會在每次迴圈體執行結束後執行一次,條件陳述式會在每次迴圈體執行之前被檢查,如果為true則繼續執行迴圈。

例:

for i:=0; i<10; i++ {
 fmt.print(a)
}

你可以在for運算式中加入任何語句,但前提是你得加入分號以區分你的語句屬於運算式的哪個部分。但也有一種情況例外,你建立的條件運算式無需條件陳述式。

你也可以在for運算式中反覆申明數組、片、字串、map或channel中的值,用法與其他語言中的for迴圈類似。

例如:

var array= [] int {1,2,3,4}
for i,v:= range array { 
 fmt.print(i,v)
}

for運算式的迴圈次數取決於索引和數組的大小,好比這裡的i和v。


在Go語言中,還存在另外兩種控制語句。if語句除了沒有大括弧包圍的條件陳述式外,與其他語言中的if語句基本相同。

例:

if a<0 { 
 fmt.print("Negative")
} else { 
 fmt.print("Positive")
}

else條件不是必須的,但一對大括弧必須完整:

if a<0 { 
 fmt.print("Negative")
}

你也可以通過使用else if建立一個符合條件運算式:

if a<0 { 
 fmt.print("Negative")
} else if a==0 { 
 fmt.print("Zero")
} else {
  fmt.print("Positive")
}

你也可以在if主體內容執行之前執行初始化語句:

if a:=myfunc() a<0 { 
 fmt.print("Negative")
}

所有在條件陳述式中建立的變數,只在條件運算式中適用。

另一種條件運算式為switch,它的存在是為了應對在一個條件中有較多選項的情況。如:

switch a {
 case 0,1:
  fmt.print("a is 0 or 1)
 case 2.3:
  fmt.print("a is 2 or 3)
 default: 
  fmt.print("a is some other value")
}

你也可以用下面的方式書寫條件陳述式:

case a<0:

在Go語言中,你無須用break跳出條件選擇。如過你想從一個case進入接著的另一個case,那麼你可以使用fallthrough語句 (註:fallthrough表示繼續執行下面的Case而不是退出Switch)。case語句是按順序執行的,一旦有相對應的情況,執行完case中的語句後程式將會自動調用break跳出選擇,因此default選項往往被放在最後。

除了對值和條件的匹配,你可以對類型進行匹配,如:

switch a.type{
 case int: 
   fmt.print("a is an int")
 case float64: 
   fmt.print("a is a float")
 default: 
   fmt.print("some other type")
}

最後,你可以使用break終止迴圈或continue終止當前迴圈並直接進入下一次迴圈,break也可以被用於switch語句中。

雖然Go語言中也有goto語句,但這還是不講為好。

下節預告

下一部分我們將會學習在Go語言中類型是如何建立對象和調用方法、介面的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.