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

18 KiB
Raw Permalink Blame History

注释

Go 语言的注释主要分成两类,分别是单行注释和多行注释。

package main

import "fmt"

/*
多行注释。
*/
func main() {
	// 单行注释。
	fmt.Printf("单行注释。")
	/*
		多行注释
	*/
	fmt.Println("多行注释。")
}

发现一个现象,写在函数上不会被格式化,在代码中会被退格格式化。

变量

声明

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
}

作用域

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
}

常量

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 特殊常量

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)

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 只能是 truefalse
  • 默认值是 false
  • if 语句可以直接使用布尔表达式

整数类型 (int, uint)

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-bit64-bit 平台上的大小可能不同
  • uint 是无符号整数,不能表示负数
  • 默认 intint6464-bit 机器)

浮点类型 (float32, float64)

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)

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)

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'runeint32
  • 双引号 "A"string
  • 字符本质上是 int32Unicode 码点)

类型转换

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]
}

  • 转换 floatint 会丢失小数部分
  • 整型可以转换为 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
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
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
}

逻辑运算符

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
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 += 5a = a + 5
-= 减后赋值 a -= 5a = a - 5
*= 乘后赋值 a *= 5a = a * 5
/= 除后赋值 a /= 5a = a / 5
%= 取模后赋值 a %= 5a = a % 5
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
package main

import "fmt"

func main() {
	a := 10
	ptr := &a // 获取变量 a 的地址

	fmt.Println("a 的地址:", ptr)
	fmt.Println("指针解引用:", *ptr) // 10
}

运算符优先级

  1. * / % << >> & &^
  2. + - | ^
  3. == != < <= > >=
  4. &&
  5. ||

流程控制

顺序结构

默认执行顺序:代码从上到下依次执行,不需要特殊控制。

package main

import "fmt"

func main() {
	fmt.Println("步骤 1")
	fmt.Println("步骤 2")
	fmt.Println("步骤 3")
}

结果

步骤 1
步骤 2
步骤 3

选择结构(if 语句)

1)基本 if 语句

package main

import "fmt"

func main() {
	num := 15
	if num > 10 {
		fmt.Println("num > 10")
	}
	fmt.Println("main 结束")
}

2if-else 语句

package main

import "fmt"

func main() {
	score := 90
	if score == 100 {
		fmt.Println("满分")
	} else {
		fmt.Println("不是满分")
	}
}

3if-else if-else 多条件判断

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

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 省略条件

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 语句,即使条件不匹配。

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

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 语句

package main

import "fmt"

func main() {
	for i := 0; i < 5; i++ {
		fmt.Println(i)
	}
}

2)变形 for 语句

省略初始值 & 结束条件

package main

import "fmt"

func main() {
	i := 0
	for i <= 5 {
		fmt.Println(i)
		i++
	}
}

无限循环

package main

import "fmt"

func main() {
	for {
		fmt.Println("死循环")
	}
}

终止循环

1break 语句

用于终止整个循环。

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 语句

用于跳过当前循环,继续执行下一个循环。

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 105 被跳过)

goto 语句

用于无条件跳转,但容易造成代码混乱,不建议使用。

goto 只能跳转到同一函数内的标签。

package main

import "fmt"

func main() {
	fmt.Println("开始")
	goto END            // 跳转到 END
	fmt.Println("不会执行") // 这行代码被跳过
END:
	fmt.Println("结束")
}

输出

开始
结束