相比很多其它流行語言,Go的語法相對簡潔。 此篇文章將介紹編程中常用的代碼元素,并展示一份簡單的Go程序代碼,以便讓剛開始學(xué)Go編程的程序員對Go代碼結(jié)構(gòu)有一個大概的印象。
簡單來講,編程可以看作是以各種方式控制和組合計算機運行中的各種操作,以達到各種各樣的目的。 一個操作可能從一個硬件設(shè)備讀取、或者向一個硬件設(shè)備寫入一些數(shù)據(jù),從而完成一個特定的任務(wù)。 對于現(xiàn)代計算機來說,最基本的操作是底層計算機指令,比如CPU和GPU指令。 常見的硬件設(shè)備包括內(nèi)存、磁盤、網(wǎng)卡、顯卡,顯示器、鍵盤和鼠標等。
直接操控底層計算機指令進行編程是非常繁瑣和容易出錯的。 高級編程語言通過對底層指令進行一些封裝和對數(shù)據(jù)進行一些抽象,從而使得編程變得直觀和易于理解。
在流行高級編程語言中,一個操作通常是通過函數(shù)(function)調(diào)用或者使用操作符(operator)運算來完成的。 大多數(shù)高級編程語言都支持一些條件和循環(huán)控制語句。 這些條件和循環(huán)控制語句可以看作是特殊的操作。 它們的語法接近于人類語言,因此一個人寫的代碼很容易被其他人理解。
在大多數(shù)高級編程語言中,數(shù)據(jù)通常被抽象為各種類型(type)和值(value)。 一個類型可以看作是值的模板。一個值可以看作是某個類型的實例。 大多數(shù)編程語言支持自定義類型和若干預(yù)聲明類型(即內(nèi)置類型)。 一門語言的類型系統(tǒng)可以說是這門語言的靈魂。
編程中常常會使用大量的值。 一些在編碼階段可確定的值可以用它們的字面形式(literal,即字面量)來表示。 為了編程靈活和不易出錯,其它的值一般使用變量(variable)和(具名)常量(named constant)來表示。
在《Go語言101》中,具名的函數(shù)、具名的值(包括變量和具名常量)、以及定義類型和類型別名將被統(tǒng)稱為代碼要素。 代碼要素名必須為標識符(identifier)。
高級編程語言代碼將被編譯器或者解釋器轉(zhuǎn)換為底層機器碼進行執(zhí)行。 為了幫助編譯器和解釋器解析高級語言代碼,一些單詞將被用做關(guān)鍵字(keyword)。 這些單詞不能被當做標識符使用。
很多現(xiàn)代高級語言使用包(package)來組織代碼。 一個包必須引入(import)另一個包才能使用另一個包中的公有(導(dǎo)出的)代碼要素。 包名和包的引入名也都必須是標識符。
盡管高級編程語言代碼比底層機器指令友好和易懂,我們還是需要一些注釋來幫助自己和其他程序員理解我們所寫的代碼。 在下一節(jié)的程序示例中,我們可以看到很多注釋。
為了對各種代碼元素有一個更清楚的認識,讓我們來看一個簡短的Go示例程序。 和很多其流行語言一樣,Go使用//
來起始一個行注釋,使用一個/*
和*/
對來包裹一個塊注釋。
下面是這個Go示例程序。請注意閱讀其中的注釋。程序之后有更多解釋。
package main // 指定當前源文件所在的包名
import "math/rand" // 引入一個標準庫包
const MaxRand = 16 // 聲明一個具名整型常量
// 一個函數(shù)聲明
/*
StatRandomNumbers生成一些不大于MaxRand的非負
隨機整數(shù),并統(tǒng)計和返回小于和大于MaxRand/2的隨機數(shù)
個數(shù)。輸入?yún)?shù)numRands指定了要生成的隨機數(shù)的總數(shù)。
*/
func StatRandomNumbers(numRands int) (int, int) {
// 聲明了兩個變量(類型都為int,初始值都為0)
var a, b int
// 一個for循環(huán)代碼塊
for i := 0; i < numRands; i++ {
// 一個if-else條件控制代碼塊
if rand.Intn(MaxRand) < MaxRand/2 {
a = a + 1
} else {
b++ // 等價于:b = b + 1
}
}
return a, b // 此函數(shù)返回兩個結(jié)果
}
// main函數(shù),或主函數(shù),是一個程序的入口函數(shù)。
func main() {
var num = 100
// 調(diào)用上面聲明的StatRandomNumbers函數(shù),
// 并將結(jié)果賦給使用短聲明語句聲明的兩個變量。
x, y := StatRandomNumbers(num)
// 調(diào)用兩個內(nèi)置函數(shù)(print和println)。
print("Result: ", x, " + ", y, " = ", num, "? ")
println(x+y == num)
}
將上面的程序代碼存盤到一個名為basic-code-element-demo.go
的文件中并使用下列命令運行此程序:
$ go run basic-code-element-demo.go
Result: 46 + 54 = 100? true
在上面的示例程序中,單詞package
、import
、const
、func
、var
、for
、if
、else
和return
均為關(guān)鍵字。 其它大多數(shù)單詞均為標識符。 請閱讀關(guān)鍵字和標識符以獲得更多關(guān)于關(guān)鍵字和標識符的信息。
四個int
(一個在第15行,另三個在第13行) 表示內(nèi)置基本類型int
。int類型是Go中的基本整數(shù)類型之一。 第5行中的16
、第17行中的0
、 第20行中的1
以及第30行的100
均為整型字面量。 第35行的"Result: "
是一個字符串字面量。 請閱讀基本類型和它們的字面量表示以獲取更多關(guān)于基本類型和它們的字面量的信息。 Go中的非基本類型(均為組合類型)將在以后的其它文章中介紹和解釋。
第20行是一個賦值語句。 第5行聲明了一個具名常量,叫做MaxRand
。 第15行和第30行使用標準變量聲明語句聲明了三個變量。 第17行的變量i
以及第33行的變量x
和y
是使用變量短聲明語句聲明的。 變量a
和b
在聲明的時候被指定為int
類型。 編譯器會自動推導(dǎo)出變量i
、num
、x
和y
的類型均為int
類型,因為它們的初始值都是整型字面量表示的。 請閱讀常量和變量以獲取什么是類型不確定值、類型推導(dǎo)、賦值、以及如何聲明變量和具名常量。
上面的示例程序中使用了很多操作符,比如第17和19行的小于比較符<
,第36行的等于比較符==
,還有第20和36行的加法運算符+
。 第35行中的+
不是一個運算符,它是一個字符串字面量中的一個字符。 一個使用操作符的操作中涉及到的值稱為操作值(有時也可稱為運算數(shù))。 請閱讀常用操作符以獲取更多關(guān)于操作符的信息。 更多操作符將在后續(xù)其它文章中介紹。
第35和36行調(diào)用了兩個內(nèi)置函數(shù)print
和println
。 從第13行到第26行聲明的函數(shù)StatRandomNumbers
在第33行被調(diào)用。 第19行也調(diào)用了一個函數(shù) Intn
。 這個函數(shù)聲明在math/rand
標準庫包中。 請閱讀函數(shù)聲明及函數(shù)調(diào)用以獲取更多關(guān)于函數(shù)聲明及函數(shù)調(diào)用的信息。
(注意,一般print
和println
這兩個內(nèi)置函數(shù)并不推薦使用。 在正式的項目中,我們應(yīng)該盡量使用fmt
標準庫包中聲明的相應(yīng)函數(shù)。 《Go語言101》只在開始的幾篇文章中使用了這兩個函數(shù)。)
第1行指定了當前源文件所處的包的名稱。 一個Go程序的主函數(shù)(main
函數(shù))必須被聲明在一個名稱為main
的包中。 第3行引入了math/rand
標準庫包,并以rand
做為引入名。 在這個包中聲明的Intn
函數(shù)將在第19行被調(diào)用。 請閱讀代碼包和包引入,以獲取更多關(guān)于代碼包和包引入的信息。
表達式、語句和簡單語句一文中介紹了什么是表達式和語句。特別地,此文列出了所有的簡單語句類型。 在Go代碼中,各種流程控制代碼塊中的某些部分必須為簡單語句,某些部分必須為表達式。
StatRandomNumbers
函數(shù)的聲明體中使用了兩個流程控制代碼塊。 其中一個是for
循環(huán)代碼塊,它內(nèi)嵌了另外一個代碼塊。 另外一個代碼塊是一個if-else
條件控制代碼塊。 請閱讀基本流程控制語法以獲取更多關(guān)于流程控制代碼塊的信息。 更多的特殊的流程控制代碼塊將在以后的其它文章中介紹。
空行常常用來增加代碼的可讀性。 上面的程序中也包涵了很多注釋,但它們大多是為了Go初學(xué)者快速理解的目的而加入的。 我們應(yīng)該盡量使代碼自解釋,只在確實需要解釋的地方進行注釋。
像很多其它流行編程語言一樣,Go也使用一對大括號{
and }
來形成一個顯式代碼塊。但是在Go代碼中,編碼樣式風(fēng)格有一些限制。 比如,很多左大括號{
不能被放到下一行。 如果,上面的StatRandomNumbers
被修改成如下所示,則上面的示例程序?qū)⒕幾g不通過。
func StatRandomNumbers(numRands int) (int, int)
{ // 編譯錯誤:語法錯誤
var a, b int
for i := 0; i < numRands; i++
{ // 編譯錯誤:語法錯誤
if rand.Intn(MaxRand) < MaxRand/2
{ // 編譯錯誤:語法錯誤
a = a + 1
} else {
b++
}
}
return a, b
}
一些程序員不是很喜歡這些限制。但是這些限制有兩個好處:
我們可以閱讀代碼斷行規(guī)則一文以獲取更多關(guān)于代碼換行規(guī)則的細節(jié)。在目前,我們最好避免將左大括號放在下一行。 或者說,每行的非空起始字符不能是左大括號(但是,請記住,這不是一個普適的規(guī)則)。
更多建議: