**本章節內容來自《菜鳥教程》,并經過整理后記錄**
導航
---
[TOC]
---
### 數據類型
- 布爾型
- 數字類型
- 字符串類型
- 派生類型
- 指針類型
- 數組類型
- 結構化類型
- Channel類型
- 函數類型
- 切片類型
- 接口類型
- Map類型
---
### 變量
- 全局變量允許聲明而不使用,但是局部變量聲明則必須使用
```
var identifier type
# 例如
var a int
a = 1
b := 2
fmt.Println(a, b)
```
```go
package main
var (
x int
y bool
)
func main() {
var a, b int
c := "shayvmo"
fmt.Println(a, b, c, x, y)
}
// 輸出
0 0 shayvmo 0 false
```
---
### 常量
```
const identifier [type] = value
// 顯式類型定義
const a string = "abc"
// 隱式類型定義
const b = 4
```
#### iota
> iota 在 const關鍵字出現時將被重置為 0(const 內部的第一行之前),const 中每新增一行常量聲明將使 iota 計數一次(iota 可理解為 const 語句塊中的行索引)
```
package main
func main() {
const (
a = iota
b
c
d = "ha"
e
f = 100
g
h = iota
i
)
fmt.Println(a, b, c, d, e, f, g, h, i)
}
```
---
### 位運算符
- `&` 按位與
- `|` 按位或
- `^` 按位異或
- `>>` 右移 右移n位,相當于是除以2的n次方
- `<<` 左移 左移n位,相當于是乘以2的n次方
---
### 條件語句
switch: 默認每個case都有break操作,只要匹配到了,則不再匹配。如果需要執行后面的case,可以使用 fallthrough
```
switch a {
case 1:
fmt.Println("a匹配上了1")
fallthrough
case 2:
fmt.Printf("a雖然匹配上了1,加上fallthrough也能執行下面的case")
default:
fmt.Println("default")
}
```
---
### 循環語句
```
for [init]; condition; [post] {}
# 例如
for i := 0; i < 10; i++ {}
i := 1;
for ; i < 10; {
i += i * 2
}
```
---
### 函數
```
func function_name([params_list]) [return_type] {
函數體
}
```
#### 函數的參數
- 值傳遞(默認)
- 引用傳遞
#### 函數用法
- 函數作為另一個函數的實參
- 閉包
- 方法
```
package main
import (
"fmt"
"strconv"
)
// 函數類型變量
type callBack func(int)
func main() {
callBackTest(2, func(i int) {
fmt.Println("回調的函數:" + strconv.Itoa(i))
})
}
func callBackTest(x int, f callBack) {
f(x)
}
```
---
### 變量作用域
- 全局
- 局部
- 形式參數
---
### 數組
```
# 聲明數組
var varible_name [size] varible_type
# 長度為10的整型數組
var a [10] int
```
初始化數組
```
# 初始化
var a = [...]int{1,2,3,4,5}
# 或
a := [...]int{2,24,42,3}
```
---
### 指針
```
# 聲明格式
var var_name *var_type
# 執行int類型的指針 a1
var a1 *int
```
---
### 結構體
```
type struct_varible_type struct {
member definition
...
member definition
}
# 初始化
variable_name := structure_variable_type {value1, value2...valuen}
# 或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
```
例如
```
package main
type Book struct {
title string
author string
book_id int
}
func main() {
var book1 Book
book1.title = "何以笙簫默"
book1.author = "顧漫"
book1.bookId = 123
}
```
#### 結構體指針
```
var struct_pointer *Book
var book1Pointer *Book
book1Pointer = &book1
fmt.Printf("%p\n", book1Pointer)
# 何以笙簫默
book1Pointer.title
```
---
### 切片
```
var identifier []type
func main() {
arr := [...]int{1,2,3}
var slice = make([]int, 5)
slice1 := make([]int, 5)
slice2 := []int {0,1,2,3,4,5,6,7}
slice3 := arr[1:]
fmt.Println(slice, slice1, slice2, slice3)
slice2 = append(slice2, 8)
slice4 := make([]int, len(slice2), cap(slice2) * 2)
copy(slice4, slice2)
printSlice(slice2)
printSlice(slice4)
fmt.Printf("slice2[1:4] = %v", slice2[1:4])
}
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d value=%v\n", len(x), cap(x), x)
}
```
#### append 和 copy
append 向切片添加元素
- 當 append 一個滿的切片時,最大長度會自動擴容,并且擴容到當前cap的2倍
copy 復制原切片到新的切片(如果需要擴容時,需要先創建一個cap更大的切片,再把原切片復制過去)
---
### 范圍Range
- 用于for循環中迭代數組(array),切片(slice),通道(channel),集合(map)的元素。
- 在數組和切片中返回索引和索引對應的值,在集合中返回key-value對
```
func testRange() {
nums := [...]int{3,4,5,2}
for _, v := range nums {
fmt.Println(v)
}
maps := map[string]string{"a": "apple", "b": "banana"}
for k, v := range maps {
fmt.Printf("key: %s value: %s\n",k ,v)
}
// 第一個是字符的索引,第二個是字符的Unicode值
for k, v := range "abcdefg" {
fmt.Printf("%d -> %d", k, v)
}
}
```
---
### Map集合
- 無序的鍵值對集合
#### 定義Map
```
var map_varible map[key_data_type]value_data_type
map_varible := make(map[key_data_type]value_data_type)
func testMap() {
map1 := make(map[string]string)
map1["a"] = "apple"
for k, v := range map1 {
fmt.Printf("%s -> %s\n", k, v)
}
// has 可以判斷集合中是否含有這個元素
value, has := map1["a"]
fmt.Println(value, has)
}
```
delete() 函數
```
func delete(m map[Type]Type1, key Type)
delete(map1, "a")
```
---
### 接口
```
// 定義接口
type interface_name interface {
method_name1 [return_type]
}
// 定義結構體
type struct_name struct {
title string
}
// 實現接口方法
func (struct_name_varible struct_name) method_name1() [return_type] {
}
```
**實例**
```
package main
import "fmt"
type Phone interface {
call()
number() string
}
type NokiaPhone struct {
}
type Iphone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("Nokia")
}
func (iphone Iphone) call() {
fmt.Println("iphone")
}
func (nokiaPhone NokiaPhone) number() string {
return "nokia-phone-135478"
}
func (iphone Iphone) number() string {
return "iphone-13123"
}
func main() {
testInterface()
}
func testInterface() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
fmt.Println(phone.number())
phone = new(Iphone)
phone.call()
fmt.Println(phone.number())
}
```
---
### 錯誤處理
```
type error interface {
Error() string
}
func testError(a int,b int) (int, error) {
if b == 0 {
return 0, errors.New("除數不能為0")
}
return a / b, nil
}
```
---
### 并發 goroutine
```
go 函數名( 參數列表 )
```
**通道channel**
> 用于傳遞數據的一個數據結構。操作符 <- 指定通道方向,發送或接收。未指定方向則是雙向通道
```
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <- c, <- c
fmt.Println(x, y, x + y)
}
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
```
**通道緩沖區**
- 第二個參數是緩沖區的大小
```
ch := make(chan int, 100)
```
**遍歷通道與關閉通道**
range 遍歷通道時,如果通道沒有關閉,會一直阻塞等到通道,這時需要主動關閉通道
```
v, ok := <-ch
```