close
Go語言是一門類C語言的編譯型語言,這樣對於第一語言為C/C++語言的同學們來說,這就是福利。Go語言簡潔易懂,本文會概要介紹其基礎知識。
 
一、Hello, World
按照慣例,介紹語法前都會先來一發Hello, World,在此也不能免俗,具體代碼如下:
package main
import "fmt"
func main(){
fmt.Printf("Hello, World\n")
}
編譯、鏈接、運行後輸出銷魂的Hello, World。不會這個的同學,請參考我的前一篇關於Go的拙文《Golang之環境配置》。
在Go語言中,程序是通過package來組織的。package 標識當前文件所屬的包,比如:前述程序第1行package main表明本文件屬於man包,包名則表示其是一個可獨立運行的包,在編譯後會生成可執行文件。通常除了main包外,其它的包最後都會生成*.a文件即包文件,並放置在$GOPATH/pkg/$GOOS_$GOARCH目錄下,以如博文《Golang之環境配置》中環境變量設置為例就是在C:\go\pkg\windows_386目錄下。
Go語言中的包類似於Python中的module,這個可以參考我的Python系列博文之《Python之模塊》,它們的優點在於程序的模塊化和可重用性。包名和包所在的文件夾名可以不相同,包名通過package 聲明而非文件夾名。
每個可獨立運行的Go語言程序,必須包含一個package main,而包main中必須包含一個入口函數main,這與C語言保持一致,而不同的是在Go語言中,main函數既沒有參數,也沒有返回值。在程序的第3行,用關鍵字func定義了main函數,如C語言一樣main函數體放在{}中。Go語言中關鍵字共25個
 
為了輸出Hello, World,應用了函數Printf,其功能同C語言中的printf,該函數來自於fmt包,因此,在第2行中導入了fmt包,即import "fmt"。在調用包中函數時,采用.的方式調用,即fmt.Printf,這一點類似於Python。
Go語言原生支持UTF-8,因此,可以用Printf函數輸出任何非ASCII碼字符,即任何字符都可以直接輸出,甚至可以用UTF-8中的任何字符作為標識符,這點在Web編程中算得上是如魚得水。
 
二、語言基礎
Go語言之所以簡潔,是因為它有一些默認的行為:
(1)大寫字母開頭的變量是可導出的,即其它包可以讀取,是公有變量;小寫字母開頭的不可導出,是私有變量。
(2)大寫字母開頭的函數也一樣,相當於class中帶public關鍵詞的公有函數;小寫字母開頭的就是private關鍵詞的私有函數。
Go程序在設計時遵循這些原則。
1、變量
Go語言定義變量方式有很多種,具體如下:
(1)使用var關鍵字。
使用var關鍵字是Go語言最基本的變量定義方式,Go語言把變量類型放在變量名後面,這點不同於C語言,具體如下:
var variableName type        //variableName為變量名,type為變量類型
var vname1, vname2, vname3 type        //定義多個變量
var variableName type = value                //定義變量並初始化,value為初始化值
var vname1, vname2, vname3 type= v1, v2, v3        //定義多個變量並初始化
var vname1, vname2, vname3 = v1, v2, v3                //簡化定義多個變量並初始化
一般腳本語言都可以根據變量值來推導出對應的類型,因此,可以更加簡化如下:
vname1, vname2, vname3 := v1, v2, v3                    //根據值推導類型即簡單聲明
簡單聲明只能用在函數內部,即只能用來定義局部變量;使用var才能在函數外部定義變量,即定義全局變量。
_即下劃線是一個特殊變量,任何賦予它的值都會被丟棄,就像黑洞一樣,比如:
_, b := 34, 35        //將值35賦給了b,同時丟棄34
在Go語言中,已聲明的變量必須使用,否則編譯時會報錯。
2、常量
在Go語言中,常量可定義為數值、布爾值或字符串等類型,具體語法如下:
const constantName = value
const Pi float32 = 3.1415926        //也可以明確指定常量類型,類似於C++中的const
3、內置基礎類型
(1)Boolean
在Go語言中,布爾值得類型為bool,值為true或false,默認為false。
var isActive bool
var enabled, disabled = true, false
(2)數值類型
(A)整數
整數類型有無符號和有符號兩種,分別是對應int和uint,這兩種類型的精度與編譯器相關。Go語言也內置了位數固定的類型:rune, int8, in16, int32, int64和byte, uint8, uint16, uint32, uint64,其中,rune是int32的別稱,byte是uint8的別稱,有了這些後跨平臺時就不需要單獨在定義一面了,非常人性化。需要註意的是,這些類型的變量之間不允許互相賦值,否則編譯時會報錯,即int和int32、int8和int32之間都不可互用。
(B)浮點數
浮點數類型有float32和float64兩種,但沒有float類型,默認是float64。
(C)復數
復數形式為RE+IMi,其中,RE為實數部分,IM為虛數部分,i是虛數單位,默認類型是complex128,即64位實數+64位虛數。也有complex64,即32位實數+32位虛數。
var c complex64 = 5+5i
fmt.Printf("Value is: %v", c)        //輸出(5+5i)
(3)字符串
在Go語言中,字符串都采用UTF-8字符集編碼,用雙引號""或者反引號``括起來定義,其類型為string。
var emptyString string = ""
在Go語言中字符串是不可變的,否則編譯時會報錯:
var s string = "hello"
s[0] = 'c'
如果需要這麽做,需要將字符串s轉換為[]byte類型後,在按照數組賦值,然後轉換回string:
s := "hello"
c := []byte(s)
c[0] = 'c'
s2 := string(c)
在Go語言中,可以使用+操作符連接兩個字符串:
s := "hello "
m := "world"
a := s + m
4、一些技巧
(1)分組聲明
在Go語言中,可以采用分組的方式同時聲明多個常量、變量或者導入多個包:
import "fmt"
import "os"
 
const i = 100
const pi = 3.1415
 
var i int
var ppi float32
可以分組寫出如下形式:
import(
"fmt"
"os"
)
 
const(
i = 100
pi = 3.1415
)
 
var(
i int
pi float32
)
除非被顯示設置初值或者iota,則每個const分組的第一常量被默認設置為0值,第二及後續常量與第一個常量值相同,如果前面那個常量的值是itoa,則它也被設置為iota。
(2)iota枚舉
Go語言裏關鍵字iota在聲明enum時使用,默認起始值是0,每調用一次加1,但每遇到一個const關鍵字,則iota會重置為0:
const(
x = iota //x==0
y = iota //y==1
z   //z==2
)
const v = iota //v==0
(3)array
array即數組,其定義方式如下:
var arr [n]type  //n表示數組長度,type表示數組元素類型
數組操作方式同其它語言,通過[]讀取或者賦值數組元素,數組下標從0開始,數組長度不可變:
var arr [10]int   //聲明長度為10,元素類型為int的數組
arr[0] = 20    //數組元素賦值,下標從0開始
a := [3]int{1, 2, 3} //聲明長度為3的int數組,元素依次初始化為1,2,3
b := [10]int{1, 2, 3} //聲明長度為10的int數組,前3個元素依次初始化為1,2,3,其它默認為0
c := [...]int{4, 5, 6} //可以用...省略長度,Go語言會自動根據元素個數計算長度
Go語言支持嵌套數組即多維數組,以二維數組為例:
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}} //聲明一個二維數組,每個以2個數組為元素,每個數組又有4個int型元素
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}  //如果內部元素和外部一樣,可以直接忽略內部元素類型
數組之間的賦值是值得賦值,即當把一個數組作為參數傳入函數的時候,傳入的是該數組的副本,而不是指針,如果要使用指針,則需要用到slice類型。
(4)slice
有時候我們並不知道數組多大合適,這就需要“動態數組”了,在Go語言中這個任務由slice來完成,但是slice並不是真正意義上的動態數組,而是一個引用類型,slice總是指向一個底層array,sliced的聲明方式與array類似,只是不需要長度:
var fslice []int  //聲明一個slice與數組類似,但不需要指定長度
slice := []byte{'a', 'b', 'c', 'd'}  //聲明並初始化slice元素
slice還可以從一個數組或slice中再次聲明,slice通過array[i:j]來獲取,其中i是數組的開始位置,j是結束位置,但不包含array[j],其長度為j-i:
var ar = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} // 聲明一個含有8個byte元素的數組
var a, b []byte  //聲明2個含所有byte的slice
a = ar[2:5]  //a指向數組的第3個元素開始,並到第5個元素結束,即a含有ar[2]、ar[3]和ar[4]
b = ar[3:5]  //b含有ar[3]和ar[4]
slice有一些簡便操作:
(A)slice的默認開始位置為0,ar[:n]等價於ar[0:n]。
(B)slice的第2個序列默認是數組的長度,ar[n:]等價於ar[n:len(ar)]。
(C)如果從一個數組裏直接獲取slice,可以這樣ar[:],等價於ar[0:len(ar)],因為默認第一個序列是0,第二個是數組的長度。
slice是引用類型,所以當被引用元素的值改變時,其它的所有引用都會改變該值。
從概念上來說slice像一個結構體,這個結構體包含三元素:
(A)一個指針,指向數組中slice指定的開始位置。
(B)長度,即slice的長度。
(C)最大長度,也就是slice開始位置到數組的最後位置的長度。
slice有幾個有用的內置函數:
(A)len獲取slice的長度。
(B)cap獲取slice的最大容量。
(C)append向slice裏面追加一個或者多個元素,然後返回一個和slice一樣類型的slice。
(D)copy函數copy從源slice的src中復制元素到目標dst,並且返回復制的元素的個數。
需要註意的是:append函數會改變slice所引用的數組的內容,從而影響到引用同一數組的其它slice。但當slice中沒有剩余空間時即cap==len,此時將動態分配新的數組空間。返回的slice數組指針指向這個空間,而原數組的內容將保持不變,其它引用此數組的slice則不受影響。
(5)map
map類似於Python中的字典,其格式為map[keyType]valueType。
map的讀取和設置與slice類似,都是通過key來操作,不同的是slice的index只能是int類型,而map只要完全定義了==與!=操作的類型都支持。
聲明一個key是字符串,值為int的字典,這種方式的聲明需要在使用之前用make初始化:
var numbers map[string] int
numbers := make(map[string]int)
numbers["one"] = 1
numbers["ten"] = 10
numbers["three"] = 3
fmt.Println("第三個數字是", numbers["three"])         //打印出:第三個數字是3
使用map時需要註意如下幾點:
(A)map是無序的,不能通過index獲取,而必須通過key獲取。
(B)map的長度是不固定的,即和slice一樣,也是一種引用類型。
(C)內置的len函數同樣適用於map,即返回map擁有的key的數量。
(D)map的值可以通過key來修改。比如:numbers["one"]=11。
map的初始化也可以通過key:val來完成,並內置有判斷是否存在key的方式,通過delete刪除map中的元素:
rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2}        //初始化map
csharpRating, ok := rating["C#"]        //map返回有兩個值,第一個值返回ok,即如果key不存在,則ok為false,否則為true,第二個返回value值
delete(rating, "C")                //刪除key為C的元素
由於map也是一種引用類型,那麽如果兩個map同時指向一個底層,則一個改變,另一個隨之也會改變。
(6)make/new操作
make用於內建類型的內存分配,包括map、slice和channel。
new用於各種類型的內存分配。Go語言中的new同C++一樣,即new(T)分配T類型的存儲空間並初始化為零值,同時返回一個指向其地址的指針。
make(T, args)只能創建map、slice和channe並且返回一個非零初始值的T類型而不是指針l。之所以會返回一個非零值,是因為這三個數據類型指向的都是數據結構的引用,因此使用前必須被初始化,make初始化了該數據結構並填充了適當的值。
所謂零值,並非是空值,而是一種變量未填充前的默認值,通常為0,但bool是false,string是“”。


Go語言基礎

arrow
arrow
    全站熱搜

    主要步驟 發表在 痞客邦 留言(0) 人氣()