## Go語言的基本語法
[TOC]
## 1.Go 語言結構
在我們開始學習 Go 編程語言的基礎構建模塊前,讓我們先來了解 Go 語言最簡單程序的結構
### Hello World 實例
Go 語言的基礎組成有以下幾個部分:
* 包聲明
* 引入包
* 函數
* 變量
* 語句 & 表達式
* 注釋
讓我們來寫一個Hello World 代碼
```
packagemain
import"fmt"
func main(){
/* 這是我的第一個程序 */
? ?fmt.Println("Hello, World!")
}
```
簡單介紹以上代碼各個部分:
1. 第一行代碼*package main*定義了包名。你必須在源文件中非注釋的第一行指明這個文件屬于哪個包,如:package main。package main表示一個可獨立執行的程序,每個 Go 應用程序都包含一個名為 main 的包。
2. 下一行*import "fmt"*告訴 Go 編譯器這個程序需要使用 fmt 包(的函數,或其他元素),fmt 包實現了格式化 IO(輸入/輸出)的函數。
3. 下一行*func main()*是程序開始執行的函數。main 函數是每一個可執行程序所必須包含的,一般來說都是在啟動后第一個執行的函數(如果有 init() 函數則會先執行該函數)。
4. 下一行 /\*...\*/ 是注釋,在程序執行時將被忽略。單行注釋是最常見的注釋形式,你可以在任何地方使用以 // 開頭的單行注釋。多行注釋也叫塊注釋,均已以 /* 開頭,并以 */ 結尾,且不可以嵌套使用,多行注釋一般用于包的文檔描述或注釋成塊的代碼片段。
5. 下一行*fmt.Println(...)*可以將字符串輸出到控制臺,并在最后自動增加換行字符 \n。
使用 fmt.Print("hello, world\n") 可以得到相同的結果。
Print 和 Println 這兩個函數也支持使用變量,如:fmt.Println(arr)。如果沒有特別指定,它們會以默認的打印格式將變量 arr 輸出到控制臺。
## 2.包的聲明
Go語言以“包”作為程序項目的筐理單位。如果要正常運行Go語言的源文件’則必須先聲明
它所屬的包。每-個Go源文件的開頭都是-個package聲明,格式如下
```
package package_name
```
package 是聲明包名的關鍵字 package_name是包的名字
**Go語言的包昌有以下幾點特性:**
1. 一個目錄下的同級文件屬于同一個包
2. 包名可以與自身目錄名不同
3. main包是Go語言應用程序的入口包,一個Go語言應用程序必須有且僅有一個main包。
如果一個程序沒有main包,則編譯時將會報錯,無法生成可執行文件
## 3.包的導入
導入的包名使用英文雙引號(” “)包圍,格式如下:
```
import ”package_name“
```
import 是導入包的關鍵字 package_name是導入包的名字
> 為了看起來直觀一般會在packagc和jmport之間空一行,沒有空格也不會報錯,實際開發過程中,編輯器一般會提示沒有導入的包或者自動幫助導入需要的包
import 也可以同時導入多個包
```
import (
"time"
"fmt"
)
```
也可以設置包的別名
```
import (
alias1 "time"
alias2 "fmt"
)
```
如果只想初始化某個包不使用導入包中的變量或者函數,則可以直接以下劃線( _ )代替別名
```
import (
_ "time"
alias2 "fmt"
)
```
>如果已經用下劃線(_)代替了別名,繼續再調用這個包,則會在編譯的時候返回”undefined:包名的錯誤。如"undefined: os"
## 4.main函數
main 函數是一種自定義函數,在Go語言中,所有函數都以關鍵字func開頭,定義格式為:
```
func 函數名 (參數列表) (返回值列表) {
函數體
}
```
具體說明如下:
1. 函數名:由字母、數字、下劃線(_)組成,具中第1個字母不能為數字,并目在同一個
包內函數名稱不能重復
2. 參數列表:一個參數由參數變量和參數類型組成,例如func foo(name string,age int)
3. 返回值列表:可以是返回值類型列表也可以是參數列表那樣的變量名與類型的組臺列表。
函數有返回值時,必須在函數體中使用return語句返回
4. 函數體:函數體星用大括號“{}"括起來的若干語句,它們完成了一個函數的具體功能
```
func main(){
? ? fmt.Println("Hello "+"World")
}
```
### 行分隔符
go 語言不需要在一行語句的最后用英文分號(;)結尾,因為Go編譯器會自動完成這些工作,如果多個語句在同一行,則必須使用英文分號(;)將他們隔開。
### 標記
Go 程序可以由多個標記組成,可以是關鍵字,標識符,常量,字符串,符號。如以下 GO 語句由 6 個標記組成:
```
fmt //關鍵字
. // 標識符
Println //關鍵字
( //符號
"Hello, World!" //字符串
) //符號
```
## 5.注釋
Go 語言中注釋分為單行注釋和多行注釋,分別如下
```
//單行注釋
```
```
/*
多行注釋
*/
```
## 6.字符串連接
Go語言的字符串可以通過“+”號實現字符串連接
```
func main(){
? ? fmt.Println("Hello "+"World")
}
```
結果為:Hello World
## 7.關鍵字
| break | default | func | interface | select |
| --- | --- |--- |--- |--- |--- |
| case| defer | go| map | struct |
| chan| else| goto| package | switch |
| const| fallthrough | if | range | type |
| continue| for | import | return | var |
除了以上介紹的這些關鍵字,Go 語言還有 36 個預定義標識符,其中包含了基本類型的名稱和一些基本的內置函數,見下表:
| append | bool |byte | cap | close |complex |
| --- | --- |--- |--- |--- |--- |--- |
| complex64 | complex128 | uint16 | copy | false |float32 |
| float64 | imag | uintptr| int | int8 |int16 |
| uint32 | int32 | int64 | iota | len |make |
| new | nil | panic | uint64 | print |println |
| real | recover | string | true | uint|uint8|
## 8.變量
>Go建議使用駝峰式命名規則,如numberList
變量命名還遵循其他的規則,比如變量由下畫線、字母、數字組成,首個字符不能是數字,并且不能使用語言預留的關鍵字。
### 使用有具體含義的命名
避免泛化的變量命名,比如用temp、i、j、k之類的變量命名,雖然它們有一定的適用場合,但在絕大多數情況下建議使用有具體含義的命名。
### 變量命名不宜過長,也不宜過短
變量命名以2~3個單詞的長度為宜。
### 變量命名中加上后綴或者前綴
這種命名方式適合變量的值有區間的情況,比如numberMax、numberMin、timeLast、timeBefore。
### 聲明與賦值
變量賦值的標準公式
```
var 變量名 [類型] = 變量名
```
多個變量賦值的標準公式為:
```
var {
變量名1 (變量類型1) = 值1
變量名2 (變量類型2) = 值2
變量名n (變量類型n) = 值n
}
```
或者多個變量和變量(直在同-行
```
var 變量名1,變量名2,變量名3 = 值1,值2,值3
```
比如:
```
//顯示聲明
var orderNo string
orderNo="2021040503938267"
//聲明變量的同時賦值
orderId := "1789789776766868"
```
哪一種更合適呢?建議使用顯式的變量聲明方式,這樣程序代碼的可讀性更好,在閱讀程序的過程中就知道數據的類型。
也可以多個變量一起聲明與賦值,如
```
var {
strOne = "a"
strTwo = "b"
strThree = "c"
}
var strOne、strTwo、strThree
strOne、strTwo、strThree= "a","b","c"
```
總結,變量命名格式有標準格式、批量格式、簡短格式
**標準格式**
```
var 變量名 變量類型
```
變量聲明以關鍵字var開頭,中間是變量名,后面是變量類型,行尾無須有分號
**批量格式**
Go 語言還提供了一個批量設置的方法,形式如下:
```
var {
age int
name string
pwd string
}
```
**簡短格式**
```
名字:=表達式
```
需要注意的是**簡短模式**有以下限制:
* 只能用來定義變量,同時會顯式初始化.
* 不能提供數據類型
* 只能用任函數內部,即不能用來聲明全局變量·
## 9.變量的作用域
變量的作用域包括局部作用域和全局作用域,即所謂的局部變量和全局變量。
>局部作用域表示變量僅在局部有效,比如在函數內,而且可以和全局的變量名相同,這時優先使用具有局部作用域的變量內的值。全局作用域表示變量全局有效,變量的聲明在函數外部。
例如以下代碼
**源碼:base/example/global_value.go**
```
/* 聲明全局變量 */
var g int
func main() {
/* 聲明局部變量 */
var a, b int
/* 初始化參數 */
a = 10
b = 20
g = a + b
fmt.Printf("結果: a = %d, b = %d and g = %d\n", a, b, g)
}
```
```
結果: a = 10, b = 20 and g = 30
```
## 10.常量
常量的值不會在運行過程中變動,更適用于全局作用域
常量的聲明格式
```
const 常量名 [類型] = 值
```
例如聲明一個常量pi的方法
```
//顯式類型聲明
const pi float32 = 3.1415926
//隱式類型聲明
const pi = 3.1415926
```
>常量的值必須是能夠在編譯時可被確定的
### 常量生成器iota
常量聲明可以使用常量生成器iota初始化,iota用于生成一組以相似規則初始化的常量,但是
不用每行都寫一遍初始化表達式
在一個const聲明語句中,在第1個聲明的常量所在的行,iota會被置為0,之后的每—個有常量聲明的行會被加1
在Go語言中,iota的用法如下:
```
type Direction int
const {
Up Direction =iota
Down
Left
Right
}
```
在以上聲明中Up的值為0, Down的值為1,其余以此類推
## 11.運算符
運算符是用來在程序運行時執行數學運算或邏輯運算的符號,
Go語言有幾十種運算符,被分成十幾個級別,有一些運算符的優先級不同有一些運算符的優
先級相同

>記不清就加括號
## 12.流程控制語句
### 邏輯運算if
格式如下:
```
if 布爾類型的條件 {
執行語句
}else if 布爾類型的條件{
執行語句
}else{
執行語句
}
```
#### 案例-條件判斷
**源碼:base/example/if.go**
```
//條件操作
func main() {
var a int = 21
var b int = 10
var c int
c = a + b
fmt.Printf("第一行 - c 的值為 %d\n", c)
c = a - b
fmt.Printf("第二行 - c 的值為 %d\n", c)
c = a * b
fmt.Printf("第三行 - c 的值為 %d\n", c)
if a == b {
fmt.Printf("第四行 - a 等于 b\n")
} else {
fmt.Printf("第五行 - a 不等于 b\n")
}
}
```
```
結果為:第五行 - a 不等于 b
```
### for 循環
Go 語言的循環語句只支持for 關鍵字,規則如下
```
for 初始值; 控制條件;值增加條件{
執行語句
}
```
當然也可以模擬do{} - while{} 語句
```
i:=0
for {
i++;
if(i>=10){
break;
}
}
```
#### 案例-素數
**源碼:base/example/for.go**
```
//循環
func main() {
var i, j int
for i = 2; i < 100; i++ {
for j = 2; j <= (i / j); j++ {
if i%j == 0 {
break
}
}
if j > (i / j) {
fmt.Printf("%d 是素數\n", i)
}
}
}
```
結果為:
```
2 是素數
3 是素數
5 是素數
7 是素數
```
#### 案例-99乘法表
**源碼:base/example/for_multiplication_table.go**
~~~
package main
import "fmt"
//99 乘法表
func main() {
for m := 1; m < 10; m++ {
for n := 1; n <= m; n++ {
fmt.Printf("%dx%d=%d ", n, m, m*n)
}
fmt.Println()
}
}
~~~
結果為:
```
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
```
### for-range 循環
for-range 循環結構使Go 語言特有的結構,可以遍歷數組、切片、字符串、map、通道( channel )
for-range 的規則如下:
```
for key,val := range 復核變量值 {
執行語句
}
```
val 始終為集臺中對應索引值的一個復制值,因此它一般只具有“只讀’’屬性,對它所做的任何修改都不會影響集合中原有的值
**源碼:base/example/range.go**
遍歷數組:
~~~
//數組的遍歷
numsArr := [5]int{1,2, 3, 4,5}
//遍歷數組
for i, num := range numsArr {
fmt.Printf("index:%d,value=%d\n", i,num)
}
~~~
遍歷切片:
~~~
//切片的遍歷
numsSlice := []int{2, 3, 4}
//遍歷數組
for i, num := range numsSlice {
fmt.Printf("index:%d,value=%d\n", i,num)
}
~~~
遍歷字符串:
~~~
//遍歷字符串
for i, c := range "GoLand" {
fmt.Printf("結果: %d %c\n", i, c)
}
~~~
遍歷map:
~~~
//range遍歷map
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
~~~
遍歷通道:
~~~
//遍歷通道
queue := make(chan string, 2)
queue <- "one"
queue <- "two"
close(queue)
for elem := range queue {
fmt.Println(elem)
}
~~~
結果為:
```
index:0,value=1
index:1,value=2
index:2,value=3
index:3,value=4
index:4,value=5
index:0,value=2
index:1,value=3
index:2,value=4
b -> banana
a -> apple
結果: 0 G
結果: 1 o
結果: 2 L
結果: 3 a
結果: 4 n
結果: 5 d
one
two
```
### switch-case 語句
Go語言改進了傳統的switch-case語句的語法設計;case與case之間是獨立的代碼塊,不
需要通過breake語句跳出當前case代碼塊以避免執行到下一行語句
代碼如下
**源碼:base/example/switch.go**
~~~
var res="a"
switch res {
case "a":
fmt.Println("結果為a")
case "b":
fmt.Println("結果為b")
case "c":
fmt.Println("結果為c")
default:
fmt.Println("結果為 default")
}
~~~
一個分支多個值時
~~~
var res="a"
switch res {
case "a","b":
fmt.Println("結果為a或b")
case "c":
fmt.Println("結果為c")
case "d":
fmt.Println("結果為d")
default:
fmt.Println("結果為 default")
}
~~~
分支表達式
~~~
var res="a"
switch {
case res=="a" || res=="b":
fmt.Println("結果為a或b")
default:
fmt.Println("結果為 default")
}
~~~
### goto 語句
在Go語言中,可以通過語句跳轉到標簽,進行代碼間的無條件跳轉,此外,goto語句在快速跳出循環也有很大的作用
例如使用goto 語句跳出循環
例如使用goto 語句統一跳轉錯誤提示
**源碼:base/example/goto.go**
~~~
//goto 使用
func main() {
for x := 0; x < 20; x++ {
for y := 0; y < 20; y++ {
if y == 2 {
// 跳轉到標簽
goto breakHere
}
}
}
// 手動返回, 避免執行進入標簽
return
// 標簽
breakHere:
fmt.Println("done")
}
~~~
### continues 語句
Go 語言的continues 語句用于結束當前語句的循環,繼續進行下一次的循環過程。它僅限在for循環內部使用,在continues 語句后面添加標簽,表示結束標簽對應的當前語句,開始下一次的循環
**源碼:base/example/continue.go**
~~~
//continue 語法
func main() {
//外層循環的標簽
OuterLoop:
//雙層循環
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
//使用 switch 進行數值分支判斷
switch i {
case 1:
//換行輸出
fmt.Println(i, j)
//退出 OuterLoop 對應的循環之外
continue OuterLoop
case 2:
fmt.Println(i, j)
continue OuterLoop
case 3:
fmt.Println(i, j)
break OuterLoop
}
}
}
}
~~~
結果為:
```
1 0
2 0
3 0
```
### bresk 語句
Go 語言的break 語句可以結束for 、switch 、select 代碼塊,還可以在break 語句后面添加標簽,可以實現快速退出某個標簽對應的代碼塊。添加的標簽必須在對應的for、switch、select 代碼塊上。
**源碼:base/example/break.go**
~~~
//break 語法
func main() {
//外層循環的標簽
OuterLoop:
//雙層循環
for i := 0; i < 5; i++ {
for j := 0; j < 5; j++ {
//使用 switch 進行數值分支判斷
switch i {
case 1:
//換行輸出
fmt.Println(i, j)
//退出 OuterLoop 對應的循環之外
break OuterLoop
}
}
}
}
~~~
結果為:
```
1 0
```
## 13.總結
本章節主要介紹了Go 語言的基本語法,有包的聲明方式、包的導入方式、main 函數的使用方式、Go語言的代碼注釋方式、字符串拼接方式(和Java 相同)、關鍵字及預定義字符的介紹,變量的聲明規范及賦值形式、全局變量和局部變量的介紹、常量的聲明規則和賦值介紹、Go 的運算符優先級介紹(記不清的時候用“()”)、流程控制語句的介紹(邏輯運算符if、switch-case,中斷語句continues、break,循環控制語句 for、for-range,跳轉語句goto)。
- 前言
- go介紹
- 準備工作
- go 環境搭建
- Go入門基礎
- 基礎語法
- 數據類型
- 基本數據類型
- 復核類型
- 函數
- 常用內置包
- 指針
- 面向對象編程
- 結構體
- 接口
- 反射
- 單元測試
- 日志處理
- Go 進階挑戰
- GoWeb開發
- HelloWorld
- HTTP的概念
- HTTP請求方法
- HTTPS通信原理
- HTTP2
- Server 端啟動的幾種方式
- Server 端路由的幾種方式
- Http請求
- Go 模板引擎
- Header
- Cookie
- Session
- Go-Mysql
- Go-orm庫
- gorm
- xorm
- beego-orm
- Go-Redis
- Redis 介紹
- Redis 入門
- Go-操作Redis
- Go-MongoDB
- MongoDB 介紹
- MongoDB 入門
- Go-操作MongoDB
- Go 高級應用
- Socket編程
- Socket 介紹
- Go Socket編程
- 文件處理
- 目錄操作
- 文件操作
- XML 操作
- JSON操作
- 并發編程
- goroutine與channel
- sync
- Web 框架
- Beego框架
- beego-init
- beego-api
- Gin框架
- Echo框架
- Iris框架
- Go實戰
- Beego 仿小米后端服務
- 實戰項目介紹
- 初始化項目
- 接口改造
- model改造
- 中間件配置
- 通用組件
- Gin 仿小米后端服務
- 項目實戰介紹
- 初始化項目
- 接口改造
- model 改造
- 登錄認證攔截
- 微服務
- 微服務介紹
- 容器化
- docker
- docker 介紹
- docker 安裝
- docker 基本操作
- docker compose安裝
- docker 安裝MongoDB
- docker 安裝mysql
- docker 安裝redis
- Kubernetes
- Kubernetes 介紹
- Kubernetes 環境搭建
- Mac 安裝 Kubernetes
- Windows 安裝Kubernetes