Files
notes/resource/go/待总结/002 Go 语言基础语法.md
2026-03-01 01:43:46 +08:00

920 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 注释
Go 语言的注释主要分成两类,分别是**单行**注释和**多行**注释。
```go
package main
import "fmt"
/*
多行注释。
*/
func main() {
// 单行注释。
fmt.Printf("单行注释。")
/*
多行注释
*/
fmt.Println("多行注释。")
}
```
> 发现一个现象,写在函数上不会被格式化,在代码中会被退格格式化。
# 变量
## 声明
```go
package main
import "fmt"
func main() {
// 1️⃣ 变量声明(包含默认值)
var name string = "田卓"
var age int = 27
var isGood bool = true
var myAge int // 默认值 0
fmt.Println("默认值示例:")
fmt.Println("name:", name)
fmt.Println("age:", age)
fmt.Println("isGood:", isGood)
fmt.Println("myAge (未赋值,默认值):", myAge)
fmt.Println()
// 2️⃣ 批量声明变量(默认值)
var (
name1 string
age1 int
)
fmt.Println("批量声明:")
fmt.Println("name1:", name1) // 默认 ""
age1 = 20
fmt.Println("age1:", age1) // 赋值后 20
fmt.Println()
// 3️⃣ 变量自动类型推导(语法糖 :=)
name2 := "田秉衡" // Go 自动推导为 string
age2 := 2 // 自动推导为 int
height := 8 // 自动推导为 int
weight := 28 // 自动推导为 int
fmt.Println("类型推导:")
fmt.Println("name2:", name2)
fmt.Println("age2:", age2)
fmt.Println("height:", height)
fmt.Println("weight:", weight)
fmt.Println()
// 4️⃣ 变量交换
nameA := "田卓"
nameB := "田秉衡"
fmt.Println("交换前:", nameA, nameB)
nameA, nameB = nameB, nameA
fmt.Println("交换后:", nameA, nameB)
fmt.Println()
// 5️⃣ 多返回值赋值(使用 `_` 忽略不需要的值)
result, _ := test() // 只取第一个返回值,忽略第二个
fmt.Println("多返回值赋值(忽略不需要的值):", result)
}
// 定义一个返回两个整数的函数
func test() (int, int) {
return 200, 200
}
```
## 作用域
```go
package main
import "fmt"
// 1️⃣ 全局变量(作用域:整个 package)
var globalVar string = "全局变量"
func main() {
// 2️⃣ 局部变量(作用域:main 函数内)
var localVar string = "局部变量"
fmt.Println("🌍 全局变量:", globalVar)
fmt.Println("🔹 局部变量:", localVar)
// 3️⃣ 代码块作用域
{
blockVar := "代码块变量"
fmt.Println("📦 代码块变量:", blockVar)
}
// ❌ 代码块变量超出作用域,下面的代码会报错
// fmt.Println(blockVar) // ❌ 编译错误:未定义 blockVar
// 4️⃣ 变量遮蔽(局部变量遮蔽全局变量)
globalVar := "局部遮蔽全局"
fmt.Println("🚧 遮蔽后的 globalVar:", globalVar)
// 5️⃣ 变量交换
a, b := "变量A", "变量B"
fmt.Println("🔄 交换前:", a, b)
a, b = b, a
fmt.Println("🔄 交换后:", a, b)
// 6️⃣ 函数参数作用域
printVar("函数参数")
// 7️⃣ 访问真正的全局变量(使用 package 级别变量)
fmt.Println("🌍 真实的全局变量仍然是:", getGlobalVar())
}
// 6️⃣ 函数参数作用域
func printVar(param string) {
fmt.Println("🎯 函数参数作用域:", param)
}
// 7️⃣ 访问全局变量的辅助函数
func getGlobalVar() string {
return globalVar
}
```
# 常量
```go
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
// 1️⃣ 基本常量声明
const URL1 string = "www.baidu.com"
fmt.Println("🌍 基本常量:", URL1)
// 2️⃣ 多常量声明
const URL2, URL3 string = "www.baidu1.com", "www.baidu2.com"
fmt.Println("🌍 多常量:", URL2, URL3)
// 3️⃣ 常量枚举(iota
const (
A = iota // 0
B // 1
C // 2
)
fmt.Println("🔢 常量 iota:", A, B, C)
// 4️⃣ `iota` 用法(位移计算)
const (
Flag1 = 1 << iota // 1 (2^0)
Flag2 // 2 (2^1)
Flag3 // 4 (2^2)
)
fmt.Println("🛠️ iota 位移:", Flag1, Flag2, Flag3)
// 5️⃣ 变量可修改,但常量不能修改
var myVar int = 100
fmt.Println("🔄 变量修改前:", myVar)
// 6️⃣ 变量地址修改(⚠️ 变量可以被 unsafe 修改,但常量不能)
myVarPtr := unsafe.Pointer(&myVar)
rv := reflect.NewAt(reflect.TypeOf(myVar), myVarPtr).Elem()
// 修改值
rv.SetInt(200)
fmt.Println("🔄 变量修改后:", myVar)
// 7️⃣ 常量的内存地址(不会被修改)
// ❌ 下面代码如果取消注释会报错:常量不能被修改
// const myConst int = 300
// fmt.Printf("🚫 常量内存地址: %p (常量不会被修改)\n", &myConst)
// rvConst := reflect.NewAt(reflect.TypeOf(myConst), unsafe.Pointer(&myConst)).Elem()
// rvConst.SetInt(500)
// fmt.Println("🚫 常量修改后:", myConst)
}
```
## iota 特殊常量
```go
package main
import "fmt"
func main() {
// 1️⃣ `iota` 基本递增
const (
a = iota // 0
b // 1 (继承 `a = iota`iota 递增)
c // 2
d = 0 // ❌ 这里手动赋值 d = 0,iota 仍然递增(跳过)
e // 0 (继承 d = 0,而不是 iota)
f = iota // 5 (iota 继续递增,从 `c = 2` 到 `iota = 5`)
g // 6
h = iota // 7 (手动写 `iota`,但值仍然递增)
)
fmt.Println("🔢 基本 iota:", a, b, c, d, e, f, g, h) // 0 1 2 0 0 5 6 7
// 2️⃣ `iota` 遇到手动赋值的影响
const (
i = iota // 0
j = 0 // ❌ 手动赋值 j = 0,但 iota 仍然递增
k = iota // 2 (iota 继续递增,从 `i = 0` 变为 `k = 2`)
)
fmt.Println("🎯 iota 断开影响:", i, j, k) // 0 0 2
}
```
# 数据类型
## 布尔类型 (bool)
```go
package main
import "fmt"
func main() {
// ✅ 布尔值只能是 true 或 false
var b1 bool = true
var b2 bool = false
// 🔹 %t 格式化布尔值
fmt.Printf("b1: %t, b2: %t\n", b1, b2)
// ✅ Go 规定:false = 0, true = 1
var num1, num2 int = 1, 2
if num1 < num2 {
fmt.Println("✅ 1 小于 2")
}
// ⚠️ 布尔类型默认值是 `false`
var b3 bool
fmt.Println("🔹 bool默认值:", b3) // 输出 false
}
```
- 布尔类型 `bool` 只能是 `true``false`
- 默认值是 `false`
- `if` 语句可以直接使用布尔表达式
## 整数类型 (int, uint)
```go
package main
import "fmt"
func main() {
// ✅ 无符号整数类型(uint
var u8 uint8 = 255
fmt.Printf("uint8: %v\n", u8)
// ✅ 有符号整数类型(int
var i8 int8 = -128
fmt.Printf("int8: %v\n", i8)
}
```
| 类型 | 描述 | 取值范围 |
| -------- | ---------- | ---------------------------------------------- |
| `uint8` | 无符号 8 位整型 | `0` - `255` |
| `uint16` | 无符号 16 位整型 | `0` - `65535` |
| `uint32` | 无符号 32 位整型 | `0` - `4294967295` |
| `uint64` | 无符号 64 位整型 | `0` - `18446744073709551615` |
| `int8` | 有符号 8 位整型 | `-128` - `127` |
| `int16` | 有符号 16 位整型 | `-32768` - `32767` |
| `int32` | 有符号 32 位整型 | `-2147483648` - `2147483647` |
| `int64` | 有符号 64 位整型 | `-9223372036854775808` - `9223372036854775807` |
- **`int` 类型** 在 `32-bit``64-bit` 平台上的大小可能不同
- **`uint` 是无符号整数,不能表示负数**
- **默认 `int``int64`64-bit 机器)**
## 浮点类型 (float32, float64)
```go
package main
import "fmt"
func main() {
// ✅ 浮点类型(默认 `float64`)
var f1 float64 = 3.141592653
var f2 float32 = 2.71
fmt.Printf("float64: %T, %.3f\n", f1, f1) // 保留3位小数
fmt.Printf("float32: %T, %.2f\n", f2, f2) // 保留2位小数
// ⚠️ 计算机存储浮点数时存在精度丢失
var num1 float32 = -123.0000901
var num2 float64 = -123.0000901
fmt.Println("float32:", num1)
fmt.Println("float64:", num2)
}
```
- `float64` **精度比 `float32` 高**
- **浮点数计算可能会有精度损失**
- **格式化输出 `%.2f` 控制小数位数**
## 特殊整数类型 (byte, rune, uintptr)
```go
package main
import (
"fmt"
"unsafe"
)
func main() {
// ✅ `byte` 是 `uint8` 的别名(常用于存储字符)
var b byte = 255
fmt.Printf("byte: %T, %v\n", b, b)
// ✅ `rune` 是 `int32` 的别名(用于存储 Unicode 字符)
var r rune = '魑'
fmt.Printf("rune: %T, %v, %c\n", r, r, r)
// ✅ `uintptr` 存储指针地址
var x int = 42
ptr := unsafe.Pointer(&x)
// 强制转换
uintPtr := uintptr(ptr)
fmt.Printf("Pointer: %v, Uintptr: %v\n", ptr, uintPtr)
}
```
- `byte` **等价于 `uint8`**,用于 **存储 ASCII 字符**
- `rune` **等价于 `int32`**,用于 **存储 Unicode 字符**
- `uintptr` **用于存储指针地址**
## 字符串类型 (string)
```go
package main
import "fmt"
func main() {
// ✅ 字符串类型
var str string = "Hello, World!"
fmt.Printf("string: %T, %s\n", str, str)
// ✅ 单引号是字符(rune),双引号是字符串(string)
v1 := 'A' // `rune`int32
v2 := "A" // `string`
fmt.Printf("rune: %T, %d\n", v1, v1) // 'A' 的 Unicode 编码值
fmt.Printf("string: %T, %s\n", v2, v2)
// ✅ Unicode 字符
v3 := '魑'
fmt.Printf("rune: %T, %d, %c\n", v3, v3, v3)
}
```
- **单引号 `'A'``rune`int32**
- **双引号 `"A"``string`**
- **字符本质上是 `int32`Unicode 码点)**
## 类型转换
```go
package main
import "fmt"
func main() {
// ✅ 浮点数转整数(丢失小数部分)
a := 5.9
b := int(a)
fmt.Printf("浮点转整型: %v\n", b) // 输出 5
// ✅ 整数转浮点数
var c int = 10
var d float64 = float64(c)
fmt.Printf("整数转浮点: %v\n", d) // 输出 10.000000
// ✅ `byte` 和 `rune` 互转
var ch rune = 'A'
fmt.Printf("字符 'A' 转 int: %v\n", int(ch)) // 65
// ✅ `string` 转 `byte`
str := "Go"
byteArr := []byte(str)
fmt.Printf("字符串转 byte: %v\n", byteArr) // [71 111]
}
```
- **转换 `float``int` 会丢失小数部分**
- **整型可以转换为 `float64`**
- **字符 (`rune`) 本质是 `int32`,可以直接转整数**
- **`string` 可以转换为 `byte[]`**
# 运算符全
## 算术运算符
| 运算符 | 描述 | 示例(a = 7, b = 3 | 结果 |
| ---- | ------------- | ---------------- | ------------------- |
| `+` | 加法 | `a + b` | `7 + 3 = 10` |
| `-` | 减法 | `a - b` | `7 - 3 = 4` |
| `*` | 乘法 | `a * b` | `7 * 3 = 21` |
| `/` | 除法 | `a / b` | `7 / 3 = 2`(整数除法取整) |
| `%` | 取模(求余数) | `a % b` | `7 % 3 = 1` |
| `++` | 自增(不支持 `++a` | `a++` | `a = a + 1` |
| `--` | 自减(不支持 `--a` | `a--` | `a = a - 1` |
```go
package main
import "fmt"
func main() {
a, b := 7, 3
fmt.Println("加法:", a+b)
fmt.Println("减法:", a-b)
fmt.Println("乘法:", a*b)
fmt.Println("除法:", a/b) // 结果是 2,整数除法取整
fmt.Println("取模:", a%b) // 余数 1
// 自增 & 自减
a++
fmt.Println("自增:", a) // 8
a--
fmt.Println("自减:", a) // 7
}
```
## 关系运算符
| 运算符 | 描述 | 示例(a = 21, b = 10 | 结果 |
| ---- | ---- | ------------------ | ------- |
| `>` | 大于 | `a > b` | `true` |
| `<` | 小于 | `a < b` | `false` |
| `>=` | 大于等于 | `a >= b` | `true` |
| `<=` | 小于等于 | `a <= b` | `false` |
| `==` | 等于 | `a == b` | `false` |
| `!=` | 不等于 | `a != b` | `true` |
```go
package main
import "fmt"
func main() {
a, b := 21, 10
fmt.Println(a > b) // true
fmt.Println(a >= b) // true
fmt.Println(a < b) // false
fmt.Println(a <= b) // false
fmt.Println(a == b) // false
fmt.Println(a != b) // true
}
```
## 逻辑运算符
```go
package main
import "fmt"
func main() {
a, b := true, false
fmt.Println("与 &&:", a && b) // false
fmt.Println("或 ||:", a || b) // true
fmt.Println("非 !:", !a) // false
}
```
## 位运算符
| 运算符 | 描述 | 示例(a = 60, b = 13) | 结果(二进制) | 结果(十进制) |
| ---- | ---- | ------------------ | ------------------------ | ---------------- |
| `&` | 按位与 | `a & b` | `0011 1100 & 0000 1101` | `0000 1100 = 12` |
| ` | ` | 按位或 | `a | b` |
| `^` | 按位异或 | `a ^ b` | `0011 1100 ^ 0000 1101` | `0011 0001 = 49` |
| `&^` | 按位清空 | `a &^ b` | `0011 1100 &^ 0000 1101` | `0011 0000 = 48` |
| `<<` | 左移 | `a << 2` | `1111 0000` | `240` |
| `>>` | 右移 | `a >> 2` | `0000 1111` | `15` |
```go
package main
import "fmt"
func main() {
a, b := 60, 13
fmt.Println("按位与 &:", a&b) // 12
fmt.Println("按位或 |:", a|b) // 61
fmt.Println("按位异或 ^:", a^b) // 49
fmt.Println("位清空 &^:", a&^b) // 48
fmt.Println("左移 <<:", a<<2) // 240
fmt.Println("右移 >>:", a>>2) // 15
}
```
## 赋值运算符
| 运算符 | 描述 | 示例 |
| ---- | ----- | ---------------------- |
| `=` | 赋值 | `a = 10` |
| `+=` | 加后赋值 | `a += 5``a = a + 5` |
| `-=` | 减后赋值 | `a -= 5``a = a - 5` |
| `*=` | 乘后赋值 | `a *= 5``a = a * 5` |
| `/=` | 除后赋值 | `a /= 5``a = a / 5` |
| `%=` | 取模后赋值 | `a %= 5``a = a % 5` |
```go
package main
import "fmt"
func main() {
a := 10
a += 5
fmt.Println("a += 5:", a) // 15
a *= 2
fmt.Println("a *= 2:", a) // 30
}
```
## 指针运算符
| 运算符 | 描述 | 示例 |
| --- | ------------- | ------------ |
| `&` | 取地址 | `ptr = &a` |
| `*` | 解引用(获取指针指向的值) | `val = *ptr` |
```go
package main
import "fmt"
func main() {
a := 10
ptr := &a // 获取变量 a 的地址
fmt.Println("a 的地址:", ptr)
fmt.Println("指针解引用:", *ptr) // 10
}
```
## 运算符优先级
**高****低**
1. `*` `/` `%` `<<` `>>` `&` `&^`
2. `+` `-` `|` `^`
3. `==` `!=` `<` `<=` `>` `>=`
4. `&&`
5. `||`
# 流程控制
## 顺序结构
**默认执行顺序**:代码从上到下依次执行,不需要特殊控制。
```go
package main
import "fmt"
func main() {
fmt.Println("步骤 1")
fmt.Println("步骤 2")
fmt.Println("步骤 3")
}
```
**结果**
```
步骤 1
步骤 2
步骤 3
```
## 选择结构(if 语句)
### 1)基本 if 语句
```go
package main
import "fmt"
func main() {
num := 15
if num > 10 {
fmt.Println("num > 10")
}
fmt.Println("main 结束")
}
```
### 2if-else 语句
```go
package main
import "fmt"
func main() {
score := 90
if score == 100 {
fmt.Println("满分")
} else {
fmt.Println("不是满分")
}
}
```
### 3if-else if-else 多条件判断
```go
package main
import "fmt"
func main() {
var score int
fmt.Println("请输入成绩:")
fmt.Scan(&score)
if score >= 90 && score <= 100 {
fmt.Println("A")
} else if score >= 80 {
fmt.Println("B")
} else if score >= 70 {
fmt.Println("C")
} else if score >= 60 {
fmt.Println("D")
} else if score < 0 || score > 100 {
fmt.Println("输入不合法")
} else {
fmt.Println("不及格")
}
}
```
## 选择结构(switch 语句)
### 1)基本 switch
```go
package main
import "fmt"
func main() {
score := 100
switch score {
case 100, 95, 91:
fmt.Println("A")
case 90:
fmt.Println("B")
case 80, 70, 60:
fmt.Println("C")
default:
fmt.Println("其他")
}
}
```
- `case` **支持多个匹配值**(如 `100, 95, 91`
- `default` **可选**
### 2switch 省略条件
```go
package main
import "fmt"
func main() {
switch {
case false:
fmt.Println("false")
case true:
fmt.Println("true")
default:
fmt.Println("其他")
}
}
```
- `switch` **默认匹配 `true`**,可以用作 `if-else if-else` 结构的替代。
### 3fallthrough 关键字
`fallthrough` 用于强制执行下一个 `case` 语句,即使条件不匹配。
```go
package main
import "fmt"
func main() {
a := false
switch a {
case false:
fmt.Println("1")
fallthrough
case true:
fmt.Println("2") // 强制执行
}
}
```
- **`fallthrough` 忽略 `case` 的匹配条件**
- **避免滥用**,否则可能产生意外行为
### 4)终止 fallthrough
```go
package main
import "fmt"
func main() {
a := false
switch a {
case false:
fmt.Println("1")
fallthrough
case true:
fmt.Println("2")
if !a {
break // 终止 `fallthrough`
}
fallthrough
default:
fmt.Println("3")
}
}
```
## 循环结构(for 语句)
### 1)基本 for 语句
```go
package main
import "fmt"
func main() {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
```
### 2)变形 for 语句
省略初始值 & 结束条件
```go
package main
import "fmt"
func main() {
i := 0
for i <= 5 {
fmt.Println(i)
i++
}
}
```
无限循环
```go
package main
import "fmt"
func main() {
for {
fmt.Println("死循环")
}
}
```
## 终止循环
### 1break 语句
用于**终止**整个循环。
```go
package main
import "fmt"
func main() {
for i := 1; i <= 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
}
```
`i == 5` 时,`break` 终止循环,输出 `1 2 3 4`
### 2continue 语句
用于**跳过当前循环**,继续执行下一个循环。
```go
package main
import "fmt"
func main() {
for i := 1; i <= 10; i++ {
if i == 5 {
continue // 跳过 5
}
fmt.Println(i)
}
}
```
输出 `1 2 3 4 6 7 8 9 10``5` 被跳过)
## goto 语句
用于**无条件跳转**,但容易造成代码混乱,不建议使用。
`goto` 只能跳转到**同一函数**内的标签。
```go
package main
import "fmt"
func main() {
fmt.Println("开始")
goto END // 跳转到 END
fmt.Println("不会执行") // 这行代码被跳过
END:
fmt.Println("结束")
}
```
**输出**
```
开始
结束
```