一通百通,Go語言入門如此輕松
沒有最完美的語言,只有最完美的使用場景。
不同語言在不同業(yè)務(wù)場景下發(fā)揮著不同的作用。
初期掌握一門編程語言,也能夠在IT 行業(yè)中游刃有余,然而,隨著在軟件開發(fā)中的經(jīng)驗積累,你可能會發(fā)現(xiàn)一門語言的局限性。不同的編程語言在不同的業(yè)務(wù)場景下發(fā)揮著不同的作用。有些語言更適合構(gòu)建大規(guī)模分布式系統(tǒng),有些語言更適合處理高并發(fā)的網(wǎng)絡(luò)請求,而有些語言則更適合開發(fā)移動應(yīng)用程序或數(shù)據(jù)科學(xué)領(lǐng)域。
然而編程的基本概念,如變量、數(shù)據(jù)類型、條件語句、循環(huán)和函數(shù)等。在大多數(shù)編程語言中都是通用的,并且可以通過類比和遷移的方式應(yīng)用于其他語言。
編程語言之間往往存在某種程度的相似性。那么本文就以這些內(nèi)容為出發(fā)點作為Go語言的敲門磚。
Part2 學(xué)習(xí)范圍
Part3 正文
調(diào)試步驟:有條件的可以在本機上安裝 go 環(huán)境,懶得折騰的可以直接利用網(wǎng)頁版開發(fā)環(huán)境:Go.Dev
1 一)Hello World
作為學(xué)習(xí)的必經(jīng)之路,我們很有必要了解一下Go語言中如何實現(xiàn) hello word 程序
package main // Go程序的包聲明。Go程序由多個包組成
import "fmt" // fmt包,它提供了格式化輸入和輸出的功能
func main() { // 程序的主函數(shù),也是程序的入口點
fmt.Println("hello world")
}
2 二)變量和數(shù)據(jù)類型
1、數(shù)據(jù)類型
定義變量之前我們需要先了解在Go語言中提供了幾種基本數(shù)據(jù)類型:
1. 布爾類型
bool,表示邏輯值,只有兩個取值:true和false。
2. 數(shù)字類型
支持整型(int)和浮點型(float)數(shù)字,并且支持復(fù)數(shù)(complex)。
3. 字符串類型
string,表示一串字符序列。是由單個字節(jié)連接起來的。Go 語言的字符串的字節(jié)使用 UTF-8 編碼標(biāo)識 Unicode 文本。
4. 派生類型
- 指針類型(Pointer Types):用于存儲變量的內(nèi)存地址。
- 數(shù)組類型(Array Types):表示固定長度的同一類型元素的集合。
- 結(jié)構(gòu)體類型(Struct Types):表示具有不同類型字段的自定義數(shù)據(jù)結(jié)構(gòu)。
- 通道類型(Channel Types):用于在Go協(xié)程之間進行通信。
- 切片類型(Slice Types):表示可變長度的元素序列。
- 映射類型(Map Types):表示鍵-值對的集合。
- 錯誤類型(Error Type):
error,表示錯誤的接口類型。
這么多類型記不住?沒關(guān)系,用到的時候自然就記住了
2、變量與常量
1)單變量聲明
在 Go 中,有兩種方式可以聲明變量
- 使用 var 關(guān)鍵字
var variablename [type] = value
看到這個有點意思,通過 var 可以想到 JavaScript,通過 variablename type 的類型聲明又可以聯(lián)想到 TypeScript,不同的是少了 :
- 使用 := 標(biāo)識符
variablename := value
在這種情況下,變量的類型是從值推斷出來的(意味著編譯器根據(jù)值決定變量的類型)。
示例:
2)多變量聲明
在 Go 中,可以在同一行中聲明多個變量。
3)常量聲明
const variablename [type] = value
關(guān)鍵字是 const,可以省略類型說明符 [type],因為編譯器可以根據(jù)變量的值來推斷其類型。
- 顯式類型定義:
const b string = "abc" - 隱式類型定義:
const b = "abc"
4)常量枚舉
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(a)
)
常量表達(dá)式中,函數(shù)必須是內(nèi)置函數(shù)
3 三)控制流程語句
1、if 語句
基本使用如下,這邊需要注意的是 條件 不需要使用 () 包裹
if condition {
} else if condition {
} else {}
2、switch 語句
使用 switch 語句來選擇要執(zhí)行的多個代碼塊之一。Go 中的語句類似于 C、C++、Java、JavaScript 和 PHP 中的 switch 語句。不同之處在于它只運行對應(yīng)匹配的代碼塊,因此不需要 break 語句。
使用須知:
- 表達(dá)式只計算一次
-
switch將表達(dá)式的值與每個case表達(dá)式的值進行比較 - 如果存在匹配項,則執(zhí)行關(guān)聯(lián)的代碼塊
- 關(guān)鍵字
default是可選的。它指定在沒有case匹配項時要運行的一些代碼
1)多用例 switch 語句
switch 語句 case 中可以為單個值有多個值:
switch _expression_ {
case x, y:
...do something
case v, w:
...do something
case z:
...do something
default:
...do something
}
3、for 語句
for 循環(huán)是 Go 中唯一可用的循環(huán)。
for statement1; statement2; statement3 {
...do something
}
使用須知:
- 語句 1 初始化循環(huán)計數(shù)器值。
- 語句 2 針對每個循環(huán)迭代計算。
- 語句3 增加循環(huán)計數(shù)器值。

1)continue
continue 語句用于跳過循環(huán)中的一次或多次迭代。然后,它繼續(xù)循環(huán)中的下一次迭代。
2)break
break 語句用于中斷/終止循環(huán)執(zhí)行。
3)range 關(guān)鍵字
關(guān)鍵字 range 用于更輕松地迭代數(shù)組、切片或映射。它同時返回索引和值。
for index, value := range array|slice|map {
...do something
}
4 四)函數(shù)
1、基本聲明
什么是函數(shù)?函數(shù)是可以在程序中重復(fù)使用的語句塊。要聲明函數(shù),需要執(zhí)行以下操作:
- 使用
func關(guān)鍵字。 - 指定函數(shù)的名稱,后跟括號 (),() 內(nèi)可添加參數(shù)列表
- 最后,在大括號 {} 內(nèi)添加定義函數(shù)應(yīng)執(zhí)行的操作的代碼。
func FunctionName(param1 type, param2 type, param3 type) {
...do something
}
2、多值返回
函數(shù)中可以返回多個值
func swap(x, y string) (string, string) {
return y, x
}
3、連續(xù)參數(shù)
當(dāng)兩個或多個連續(xù)的命名函數(shù)參數(shù)共享一個類型時,可以省略除最后一個之外的所有類型。
5 五)數(shù)據(jù)結(jié)構(gòu)
1、數(shù)組
數(shù)組用于在單個變量中存儲相同類型的多個值,而不是為每個值聲明單獨的變量。
1)創(chuàng)建方式
- 使用數(shù)組字面量初始化:
array := [size]Type{element1, element2, ...}
這種方式直接使用數(shù)組字面量來初始化數(shù)組,并提供初始元素。例如:
numbers := [5]int{1, 2, 3, 4, 5}
- 聲明數(shù)組后逐個賦值:
var array [size]Type
array[index] = value
這種方式先聲明一個數(shù)組,然后逐個為數(shù)組元素賦值。例如:
var numbers [2]int
numbers[0] = 1
numbers[1] = 2
- 使用數(shù)組初始化表達(dá)式:
array := [...]Type{element1, element2, ...}
這種方式使用 ... 來讓編譯器根據(jù)提供的初始元素數(shù)量自動推斷數(shù)組的大小。例如:
numbers := [...]int{1, 2, 3, 4, 5}
上述代碼將根據(jù)提供的 5 個初始元素推斷出數(shù)組的大小為 5。
需要注意的是,數(shù)組的長度在聲明后是固定的,無法更改。如果需要動態(tài)長度的序列,可以使用切片(slice)類型。
2)常見操作
-
len():返回數(shù)組的長度,即數(shù)組中元素的個數(shù)。 -
for循環(huán):可以使用for循環(huán)和數(shù)組的長度來遍歷數(shù)組中的元素。 -
索引訪問:通過索引操作符[]來訪問和修改數(shù)組中的元素。 -
多維數(shù)組:Go語言支持多維數(shù)組,可以使用嵌套的方式創(chuàng)建和訪問多維數(shù)組。
2、切片
切片(slice)是一種動態(tài)長度的數(shù)據(jù)結(jié)構(gòu),它是對底層數(shù)組的一種引用。切片提供了一種方便且靈活的方式來操作和管理數(shù)據(jù)集合。切片由以下三個部分組成:
- 指針(Pointer):指向底層數(shù)組的第一個元素。
- 長度(Length):切片當(dāng)前包含的元素個數(shù)。
- 容量(Capacity):底層數(shù)組從切片的起始位置到數(shù)組末尾的元素個數(shù)。
1)創(chuàng)建方式
以下是幾種常見的切片創(chuàng)建方式:
- 使用切片字面量初始化:
slice := []Type{element1, element2, ...}
這種方式直接使用切片字面量來初始化切片,并提供初始元素。例如:
numbers := []int{1, 2, 3, 4, 5}
- 使用 make() 函數(shù)創(chuàng)建指定長度的切片:
slice := make([]Type, length)
這種方式使用 make() 函數(shù)創(chuàng)建指定長度的切片,初始值為該類型的零值。例如:
numbers := make([]int, 5)
上述代碼將創(chuàng)建一個包含 5 個整數(shù)的切片。
- 使用 make() 函數(shù)創(chuàng)建指定長度和容量的切片:
slice := make([]Type, length, capacity)
這種方式使用 make() 函數(shù)創(chuàng)建指定長度和容量的切片。length 表示切片的長度,capacity 表示底層數(shù)組的容量,初始值為該類型的零值。例如:
numbers := make([]int, 5, 10)
上述代碼將創(chuàng)建一個長度為 5,容量為 10 的切片。
- 通過切片表達(dá)式(Slice Expression)從現(xiàn)有切片或數(shù)組創(chuàng)建切片:
slice := existingSliceOrArray[start:end]
這種方式使用切片表達(dá)式從現(xiàn)有的切片或數(shù)組中創(chuàng)建一個新的切片。start 表示起始索引(包含),end 表示結(jié)束索引(不包含)。例如:
numbers := []int{1, 2, 3, 4, 5}
subSlice := numbers[1:3]
上述代碼將從 numbers 切片中創(chuàng)建一個新的切片 subSlice,包含索引 1 到索引 2 的元素。
2)常見操作
切片還有一些內(nèi)置函數(shù)和操作符,可以方便地進行切片的創(chuàng)建、修改和操作,例如:
-
append():用于向切片末尾添加元素,可以動態(tài)擴展切片的長度。 -
copy():用于復(fù)制切片的內(nèi)容到另一個切片或數(shù)組。 -
len():返回切片的長度。 -
cap():返回切片的容量。
切片是引用類型,多個切片可以共享同一個底層數(shù)組。當(dāng)對一個切片進行修改時,其他共享同一底層數(shù)組的切片也會受到影響。
3)與數(shù)組的差異
使用切片相比數(shù)組的優(yōu)勢在于其動態(tài)性和靈活性,能夠根據(jù)需要動態(tài)地調(diào)整長度,并且可以方便地進行切片的操作和擴展。
- 長度的靈活性:數(shù)組具有固定的長度,切片具有動態(tài)長度
- 內(nèi)存管理:數(shù)組在聲明時會分配一段連續(xù)的內(nèi)存空間,而切片則是一個引用類型,它包含了指向底層數(shù)組的指針、長度和容量。
- 傳遞和賦值行為:數(shù)組在傳遞給函數(shù)或賦值給新變量時會進行值拷貝,這意味著會復(fù)制整個數(shù)組的內(nèi)容。而切片在傳遞和賦值時是傳遞的引用,不會復(fù)制底層數(shù)組的內(nèi)容,多個切片可以共享同一個底層數(shù)組。
- 動態(tài)操作:由于切片具有動態(tài)長度,可以使用內(nèi)置函數(shù)
append和copy來動態(tài)擴展切片的長度和復(fù)制切片的內(nèi)容。而數(shù)組的長度固定,無法直接進行動態(tài)操作,需要創(chuàng)建一個新的數(shù)組并進行元素的復(fù)制。
在實際的開發(fā)中,切片比數(shù)組更常用,切片提供了靈活性和便利性,同時可以避免不必要的內(nèi)存復(fù)制。數(shù)組通常用于特定的場景,比如需要確切長度和固定內(nèi)存布局的情況。
3、Map
1)基本概念
- Map 是一種無序的鍵值對的集合。它同時是一種集合,所以我們可以像迭代數(shù)組和切片那樣迭代它。不過,Map 是無序的,遍歷 Map 時返回的鍵值對的順序是不確定的。
- 在獲取 Map 的值時,如果鍵不存在,返回該類型的零值,例如 int 類型的零值是 0,string 類型的零值是 ""。
- Map 是引用類型,如果將一個 Map 傳遞給一個函數(shù)或賦值給另一個變量,它們都指向同一個底層數(shù)據(jù)結(jié)構(gòu),因此對 Map 的修改會影響到所有引用它的變量。
2)創(chuàng)建方式
- 利用內(nèi)建函數(shù) make 創(chuàng)建
// 創(chuàng)建一個空的 Map
m := make(map[string]int)
// 創(chuàng)建一個初始容量為 10 的 Map
m := make(map[string]int, 10)
- 使用字面量創(chuàng)建
// 使用字面量創(chuàng)建 Map
m := map[string]int{
"apple": 1,
"banana": 2,
"orange": 3,
}
4、結(jié)構(gòu)體
1)基本概念
在 Go 編程語言中,是沒有類似于其他面向?qū)ο缶幊陶Z言中的傳統(tǒng)對象的概念。
Go 是一種結(jié)構(gòu)化編程語言,它鼓勵使用結(jié)構(gòu)體(struct)和方法(method)來組織和抽象代碼。
結(jié)構(gòu)體可以包含字段(fields),這些字段可以是不同的數(shù)據(jù)類型,如整數(shù)、字符串、數(shù)組等。結(jié)構(gòu)體還可以擁有方法,方法是與結(jié)構(gòu)體關(guān)聯(lián)的函數(shù)。
盡管 Go 中沒有傳統(tǒng)意義上的對象,但可以通過結(jié)構(gòu)體和方法來實現(xiàn)面向?qū)ο蟮木幊田L(fēng)格。你可以將結(jié)構(gòu)體看作是數(shù)據(jù)的容器,方法則可以看作是操作這些數(shù)據(jù)的函數(shù)。通過定義方法,可以在結(jié)構(gòu)體上執(zhí)行各種操作,從而實現(xiàn)面向?qū)ο蟮姆庋b、繼承和多態(tài)等概念。
2)繼承
Go 編程語言中,沒有傳統(tǒng)意義上的類繼承的概念,但是可以通過其他方式實現(xiàn)類似的功能。可以通過 結(jié)構(gòu)體嵌入 來實現(xiàn)一種類似于繼承的行為。
3)聲明方式
結(jié)構(gòu)(結(jié)構(gòu)的縮寫)用于將不同數(shù)據(jù)類型的成員集合創(chuàng)建到單個變量中。數(shù)組用于將相同數(shù)據(jù)類型的多個值存儲到單個變量中,而結(jié)構(gòu)用于將不同數(shù)據(jù)類型的多個值存儲到單個變量中。
定義
type structName struct {
member1 datatype;
member2 datatype;
member3 datatype;
...
}
使用
- 使用 var 關(guān)鍵字
var v1 Vertex這里我們并不需要為結(jié)構(gòu)初始化 - 使用 := 標(biāo)識符
v1 := Vertex{}
嵌套結(jié)構(gòu) 寫法1:
寫法2:
5、接口
Go 語言中的接口是隱式實現(xiàn)的,也就是說,如果一個類型實現(xiàn)了一個接口定義的所有方法,那么它就自動地實現(xiàn)了該接口。因此,我們可以通過將接口作為參數(shù)來實現(xiàn)對不同類型的調(diào)用,從而實現(xiàn)多態(tài)。
// 定義接口
type interfaceName interface {
method_name1 [return_type]
method_name2 [return_type]
}
// 定義結(jié)構(gòu)體
type structName struct {
/* variables */
}
// 實現(xiàn)接口方法
func (struct_name structName) methodName() [returnType] {
/* 方法實現(xiàn) */
}
例子:
6、指針
在 Go 中,指針(pointer)是一種變量,它存儲了一個值的內(nèi)存地址。換句話說,指針指向內(nèi)存中存儲的數(shù)據(jù)的位置。
當(dāng)用于操作變量時,& 和 * 是 Go 語言中的兩個操作符,具有不同的含義。
-
&操作符(取地址操作符):
- 當(dāng)用于變量之前,
&操作符用于獲取變量的內(nèi)存地址。 - 例如:
&x表達(dá)式表示獲取變量x的內(nèi)存地址。
* 操作符(解引用操作符):
- 當(dāng)用于指針變量之前,
*操作符用于獲取指針指向位置的值。 - 例如:
*ptr表達(dá)式表示獲取指針ptr指向位置的值。
這兩個操作符在使用指針時經(jīng)常一起使用,配合使用可以實現(xiàn)指針的創(chuàng)建、操作和訪問。例子:
6 六)異常
Go 中,通過顯式的、單獨的返回值來傳達(dá)錯誤是慣用的。Go語言鼓勵使用返回錯誤值的方式來處理異常情況,而不是通過拋出和捕獲異常來處理錯誤。
Go 語言通過內(nèi)置的錯誤接口提供了非常簡單的錯誤處理機制。error 類型是一個接口類型,定義如下:
type error interface {
Error() string
}
我們可以在編碼中通過實現(xiàn) error 接口類型來生成錯誤信息。
7 七)并發(fā)
在Go語言中,使用并發(fā)可以通過goroutine和通道(channel)來實現(xiàn)。Goroutine是一種輕量級的線程,可以與其他goroutine并發(fā)運行,而通道是用于goroutine之間進行通信和數(shù)據(jù)同步的機制。
1)Goroutine
Go 允許使用 go 語句開啟一個新的運行期線程, 即 goroutine,以一個不同的、新創(chuàng)建的 goroutine 來執(zhí)行一個函數(shù)。同一個程序中的所有 goroutine 共享同一個地址空間。
2)Channel
通道(channel)是用來傳遞數(shù)據(jù)的一個數(shù)據(jù)結(jié)構(gòu)。可用于兩個 goroutine 之間通過傳遞一個指定類型的值來同步運行和通訊。操作符 <- 用于指定通道的方向,發(fā)送或接收。如果未指定方向,則為雙向通道。
ch <- v // 把 v 發(fā)送到通道 ch
v := <-ch // 從 ch 接收數(shù)據(jù); 并把值賦給 v
注意:默認(rèn)情況下,通道是不帶緩沖區(qū)的。發(fā)送端發(fā)送數(shù)據(jù),同時必須有接收端相應(yīng)的接收數(shù)據(jù)。
通道緩沖區(qū)
通道可以設(shè)置緩沖區(qū),通過 make 的第二個參數(shù)指定緩沖區(qū)大小:
ch := make(chan int, 100)
- 帶緩沖區(qū)的通道允許發(fā)送端的數(shù)據(jù)發(fā)送和接收端的數(shù)據(jù)獲取處于異步狀態(tài),就是說發(fā)送端發(fā)送的數(shù)據(jù)可以放在緩沖區(qū)里面,可以等待接收端去獲取數(shù)據(jù),而不是立刻需要接收端去獲取數(shù)據(jù)。
- 由于緩沖區(qū)的大小是有限的,所以還是必須有接收端來接收數(shù)據(jù)的,否則緩沖區(qū)一滿,數(shù)據(jù)發(fā)送端就無法再發(fā)送數(shù)據(jù)了。
注意:如果通道不帶緩沖,發(fā)送方會阻塞直到接收方從通道中接收了值。如果通道帶緩沖,發(fā)送方則會阻塞直到發(fā)送的值被拷貝到緩沖區(qū)內(nèi);如果緩沖區(qū)已滿,則意味著需要等待直到某個接收方獲取到一個值。接收方在有值可以接收之前會一直阻塞。
通道遍歷
Go 通過 range 關(guān)鍵字來實現(xiàn)遍歷讀取到的數(shù)據(jù),類似于與數(shù)組或切片。格式如下:
v, ok := <-ch
- 如果通道中有可接收的值,那么接收操作會成功,將該值賦給變量
v,同時ok的值為true。 - 如果通道已經(jīng)關(guān)閉且沒有可接收的值,那么接收操作會立即返回,并將變量
v的零值賦給它,同時ok的值為false。
defer 是 Go 語言中的一個關(guān)鍵字,用于延遲(defer)函數(shù)或方法的執(zhí)行。當(dāng)在函數(shù)或方法中使用 defer 關(guān)鍵字來延遲函數(shù)的執(zhí)行時,被延遲執(zhí)行的函數(shù)會在包含它的函數(shù)或方法即將返回之前被調(diào)用。
通過本文的介紹,你應(yīng)該對Go語言的入門有了更好的了解。在繼續(xù)深入學(xué)習(xí)Go語言的過程中,你將會發(fā)現(xiàn)它的強大之處。你可以進一步學(xué)習(xí)高級的并發(fā)模型、標(biāo)準(zhǔn)庫中豐富的功能和第三方庫的使用,以及構(gòu)建實際應(yīng)用程序的最佳實踐。
希望本文能夠為你提供一個良好的起點,激發(fā)你對Go語言的興趣,并為你進一步探索和學(xué)習(xí)提供指導(dǎo)。
