Go:關鍵字與預定義標識符
語法是一門編程語言的基礎,而關鍵字又是語法的基礎,我們通過這些關鍵字構建出一個個應用程序。不知道大家是不是和我一樣,對於這些語法,通常採用 “熟能生巧” 的辦法掌握,很少系統的記憶。直到有一次,編寫 switch
語句時,在沒有添加 break
的情況下,case
匹配成功後卻未繼續往下執行,這是爲什麼?原來 ,Go 語言的 switch case
自帶 break
,如果希望繼續往下執行,則需要用到fallthrough
關鍵字。原來如此,這個錯誤似乎有些低級,只怪自己沒有熟練的掌握關鍵字。那有沒有辦法,即便一個新手,沒有那麼多 coding 經驗,也不會在這種問題上犯錯誤?我的建議是,從掌握關鍵字開始,當然也離不開 36 個預定義標識符,咱們一起來看看吧。
爲了方便記憶,我將關鍵字與預定義標識符重新整理並按功能或創建方式進行了分組。
關鍵字
關鍵字是由一組具有特殊含義的單詞組成,開發者在聲明變量名、函數名等標識符時是禁止使用的。通過關鍵字,可以大致看出一門編程語言的特點,關鍵字是很適合作爲了解編程語言的入門方式。
與其他編程語言相比,Go 語言的關鍵字非常之少,只有 26 個。這些關鍵字的功能包括聲明變量名、常量名、方法名、創建新類型、條件語句、循環語句等,Go 語言的 36 個預定義標識符也是由它們定義的。
聲明關鍵字
先來了解一下聲明關鍵字,代碼程序本質上是對一堆數據進行操作,這些數據通過變量名、或常量名等標識符保存在內存中,之後我們操作標識符即可。但源碼中可能存在多種關鍵字或標識符,編譯器難以僅僅根據標識符辨別變量、常量。所以需要通過聲明關鍵字進行,其中,var
聲明變量名、const
聲明常量名、type
聲明新類型或類型別名、func
聲明一個方法或函數、package
則用來聲明包名。
var
:聲明未初始化的類型變量,變量名應遵循駝峯法,使用MixedCaps
或mixedCaps
。
這個關鍵字相信大家都不陌生,它是類型變量聲明方式之一,另外 Go 語言還提供短聲明方式,但它不在關鍵字範圍內,所以這裏不做介紹。與其它聲明方式不同,需要格外注意的是:用 var
聲明的變量是未初始化、不佔用內存空間的。系統會默認將變量值設置成類型的零值,如數值變量的默認值爲 0 ,字符串變量的默認值爲空,如果是接口或通道,則默認 nil
。通過 var
可以一次聲明一個或多個變量。
我們通常使用 var
聲明一般類型變量,或在函數體外部聲明全局變量。由於變量未初始化,如果創建的是切片、映射或通道變量,是無法直接使用的,因此在創建上述幾類變量時,建議使用內置函數 make()
。
// 聲明一個 int 類型的變量
var a int
// 聲明多個 int 類型的變量
var b, c, d int
// 聲明一組不同類型變量
var (
e int
f string
)
// ...
const
:聲明一個或多個常量。常量命名時與變量一樣,也應遵循駝峯法。
常量值只能是數字、字符、字符串或布爾值,聲明以後不能再修改。設置超過一個的常量時,可以像 var
聲明變量那樣,使用括號將常量組合在一起。
Go 語言中沒有枚舉類型 (enum),不過可以通過 const
聲明一組常量,再使用預定義標識符 iota
生成枚舉值來實現。
// 聲明一個常量
const a = 1 // 1
// 聲明多個常量和實現一個簡單的枚舉
const (
b = 2 // 2
c = 3 // 3
d = iota // 2
e // 3
f // 4
)
type
:聲明新類型。
Go 語言的類型非常靈活,我們可以根據需求,通過 type
關鍵字創建類型,或定義類型別名。預定義標識符中的基本類型便是由 type
創建,在開發過程中多用於創建結構體或接口類型。
// 創建新類型 bool
type bool bool
// 創建類型別名 byte
type byte = uint8
// 創建結構體 Scanner
type Scanner struct {
// ...
}
// 創建接口 error,並定義 Error 方法
type error interface {
Error() string
}
func
:用來聲明方法或函數。一般採用駝峯命名,但如果該方法或函數需要在包外面使用,首字母要大寫。
Go 語言的方法與函數很相似,在 func
和方法名之間加了一個參數的就是方法,用於定義類型的行爲,沒有加參數的叫函數。方法跟函數都可以有任意多參數跟返回值。
// 聲明一個結構體類型
type Scanner struct {
// ...
}
// 聲明一個方法:用於定義結構體 Scanner 的行爲
func (s *Scanner) next() {
// ...
}
// 聲明一個函數
func next() {
// ...
}
// 聲明一個匿名函數
func {
}
package
:聲明包名稱,同一目錄下的包名需要保持一致。
// main 包
package main
創建類型關鍵字
Go 語言除了數值、布爾、字符串等基本類型,還有一些派生類型,根據開發需求通過關鍵字定義:保存鍵值對的映射(map
)類型、可以包含任何類型的結構體(struct
)、爲類型定義方法的接口(interface
)類型、併發需要用到的 Goroutine
和通道(chan
)類型等。
map
:映射是內置的數據結構,用來保存鍵值對的無序集合。
一般使用 make()
函數創建,大部分基本類型都可以當做映射類型的鍵,但所有鍵的類型必須相同。當使用 delete()
刪除不存在的鍵時,程序不會報錯,而是返回對應類型的零值。由於映射屬於引用類型,不管保存了多少數據,傳遞上都很廉價。
// 創建一個空的映射並填充數據
a := make(map[int]string)
a[1] = "a"
a[2] = "b"
struct
:結構體類型。
使用聲明關鍵字 type
與結構類型 struct
創建一個結構體類型,它主要用於聚合和嵌套,結構體內可以包含任何類型的值,甚至一個結構體。不過需要注意的是,當結構體內嵌套了一個結構體,並且它們擁有相同的變量名時,最外層會被優先調用。
type Scanner struct {
// immutable state
file *token.File // source file handle
dir string // directory portion of file.Name()
src []byte // source
err ErrorHandler // error reporting; or nil
mode Mode // scanning mode
// ...
}
interface
:接口類型。
使用聲明關鍵字 type
與接口類型 interface
創建一個接口。在接口裏,我們爲類型聲明一個或多個方法簽名。代碼中經常看到的 interface{}
表示空接口,它接受任意類型值,但是當我們使用該值時,需要進行類型斷言,switch
的類型開關便是用於接口類型。
type Reader interface {
Read(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
chan
:通道類型。
使用 make()
函數創建,爲併發提供一種無鎖通信方式,用於解決多個併發之間的通信問題。在創建通道時,可設置緩衝區,設置了緩衝區的通道又叫非阻塞通道,未設置緩衝區通道叫阻塞通道。
// 創建帶緩衝區通道
a := make(chan string,5)
// 創建不帶緩衝區通道
b := make(chan string)
go
:創建一個goroutine
用來處理併發。
創建 goroutine
處理併發,讓程序執行代碼的同時並行去做另外一些事情,多個 goroutine
之間使用通道傳輸數據。
// 創建 goroutine
go func(){
//..
}
創建條件語句關鍵字
if
、if...else
:Go 的if
語句,除了習慣用法,它還支持在語句中使用:=
聲明局部變量再判斷, 變量聲明語句與判斷中間使用分號進行分割。if
語句裏可以使用關鍵字break
、continue
、goto
、return
控制流程。
if i == 0 {
// ...
}
if i := len(s); i >= 0 {
// ...
}
if !ok {
// ...
}
-
switch
、case
:switch
用於判斷多個值。Go 語言有兩種類型的switch
語句,分別是表達式開關和類型開關,類型開關只能用於接口類型的值。還有,Go 語言中的switch
默認情況下每個case
後自帶break
, 所以不會自動向下貫穿,反之,可以使用關鍵字fallthrough
。 -
select
:與switch
相似,區別是它只適用於通道。
創建循環語句關鍵字
for
:在 Go 語言裏沒有while
與do-while
語句, 統一用for
實現 。它支持無限循環、while
循環、普通循環三個形式。在語句中隨時使用break
終止或使用continue
進行下一次迭代。
// 無限循環
for {
// ...
}
// while循環
for booleanExpreesion {
// ...
}
// 一般使用
for i=0;i<=100;i++{
// ...
}
for...range
:用於遍歷字符串、數組、切片、映射、通道。range
是 Go 語言提供的一個語法糖,內部針對不同類型有不同的實現,因爲range
使用副本,性能上比for
差,也不能修改所遍歷元素的值。使用空白標識符 (_
) 丟棄不需要的值可提升代碼性能。
流程控制語句關鍵字等
-
goto
:通過標籤進行代碼中的無條件跳轉,不過我們一般不提倡使用。 -
default
:設置默認值。應用範圍:switch
與select
語句。 -
break
:代碼結束塊。應用範圍:for
、switch
、select
語句。 -
continue
:跳過當前循環的剩餘語句,然後進行下一輪循環。應用範圍:for
循環。 -
case
:開關語句。應用範圍:switch
、select
語句。 -
fallthrough
:switch
默認情況下case
自帶break
,匹配成功後就不會繼續往下執行,如果需要執行後面的case
,可以使用fallthrough
。 -
return
:返回值。 -
defer
:defer
延遲一個函數或方法的執行,如果有多個defer
語句,遵循後進先出的原則,常用在文件關閉、通道關閉、捕獲異常。 -
import
:引用包。
預定義標識符
Go 語言的預定義標識符由類型、值、函數三部分組成,它們也叫內置類型、內置值、內置函數,通過var
、type
、const
、func
這 4 個關鍵字定義。其中,內置類型分爲數值、字符串、布爾,我們前面說到的基本類型便是指這些。而內置的函數則主要針對非內置類型,如切片、映射、通道等特殊類型的操作,除此之外,還有異常處理函數。這裏僅介紹內置函數。
-
append()
:往切片中追加元素,切片容量不足時自動擴容。應用範圍:切片。 -
copy()
:複製切片。應用範圍:切片。 -
delete()
:刪除元素。應用範圍:映射 (map
)。 -
len()
:計算長度,應用範圍:數組、切片、字符串、通道(chan
)。 -
cap()
:計算容量。應用範圍:數組、切片、通道(chan)。 -
make()
:創建並初始化。應用範圍:切片、映射(map)、通道(chan
)。 -
new()
:爲類型分配內存空間,返回值爲指針。適用於值類型,如數組、結構體等。new()
它與make()
的區別是,make()
返回值是類型。 -
complex()
、real()
、imag()
:複數類型。 -
close()
:關閉通道。應用範圍:通道(chan
)。 -
panic()
:屬於異常處理函數,會產生一個運行時錯誤並終止程序,一般用在早期開發或發佈階段之前。 -
recover()
:同屬於異常處理函數,由於panic
會導致程序終止,因此一般不會用於線上,但如果希望在線上也保留panic()
,則需要添加recover()
避免中斷,我們還可以創建一個error
值,將panic()
轉換成錯誤。 -
print()
:輸出到控制檯。 -
println()
:輸出到控制檯並換行。
總結
這篇文章是對 Go 語言基礎的簡單介紹,更多的是對關鍵字和預定義標識符的歸納總結,幫助形成基本構架認知。在介紹有的關鍵字與預定義標識符時,雖是寥寥幾筆,但並不能因此認爲它不重要,或簡單好懂,它的原理以及操作運用可能遠比我們想象中要複雜,甚至還有一些意想不到的用途,後面的文章中我們會挑選一些來做深度解析。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/tr6JwRV93IJtSXdRB6xAOQ