一、变量与常量声明
var - 变量声明
var name string = "Go"
var age = 25
var x, y int = 1, 2
var count int
var price float64
var isReady bool
var text string
var numbers []int
var data map[string]int
var ptr *int
简短声明 :=
func main() {
name := "Alice"
count := 10
a, b := 1, "hello"
}
const - 常量声明
const Pi = 3.14159
const MaxUsers = 1000
const (
StatusOK = 200
StatusNotFound = 404
StatusServerError = 500
)
const (
Monday = iota + 1
Tuesday
Wednesday
Thursday
Friday
)
const (
_ = iota
KB = 1 << (10 * iota)
MB
GB
)
const (
Zero = iota
One
Two
)
const (
Sunday = iota
Monday2
Tuesday2
)
const (
A, B = iota, iota + 1
C, D
E, F
)
二、make 与 new
make - 创建并初始化引用类型
s1 := make([]int, 5)
s2 := make([]int, 3, 10)
m1 := make(map[string]int)
m2 := make(map[string]int, 10)
ch1 := make(chan int)
ch2 := make(chan int, 3)
new - 分配内存并返回指针
p := new(int)
*p = 42
type Point struct { X, Y int }
pt := new(Point)
pt.X = 10
pt.Y = 20
make vs new 对比
slice := make([]int, 3)
ptr := new([]int)
*ptr = make([]int, 3)
三、基本数据结构
数组(固定长度)
var arr1 [3]int
arr2 := [3]int{1, 2, 3}
arr3 := [...]int{1, 2, 3, 4}
arr4 := [2][3]int{{1,2,3}, {4,5,6}}
arr2[0] = 10
fmt.Println(len(arr2))
fmt.Println(arr2[1])
arr := [3]int{1, 2, 3}
func contains(arr [3]int, target int) bool {
for _, v := range arr {
if v == target {
return true
}
}
return false
}
arr := [3]int{1, 2, 3}
if contains(arr, 2) {
fmt.Println("数组包含2")
}
slice := []int{1, 2, 3}
切片(动态数组)
slice1 := []int{1, 2, 3}
slice2 := make([]int, 5)
var slice3 []int
slice1 = append(slice1, 4, 5)
copy(slice2, slice1)
fmt.Println(len(slice1))
fmt.Println(cap(slice1))
arr := [5]int{1,2,3,4,5}
s1 := arr[1:4]
s2 := arr[:3]
s3 := arr[2:]
映射(字典)
m1 := map[string]int{"a": 1, "b": 2}
m2 := make(map[string]int)
var m3 map[string]int
m1["c"] = 3
val := m1["a"]
delete(m1, "b")
val := m1["a"]
val2 := m1["x"]
value, exists := m1["x"]
if val, ok := m1["a"]; ok {
fmt.Println("键存在,值为:", val)
} else {
fmt.Println("键不存在")
}
m := map[string]int{"apple": 5, "banana": 3}
if value, exists := m["apple"]; exists {
fmt.Printf("键'apple'存在,值为: %d\n", value)
} else {
fmt.Println("键'apple'不存在")
}
if _, exists := m["orange"]; exists {
fmt.Println("键'orange'存在")
} else {
fmt.Println("键'orange'不存在")
}
if m["grape"] != 0 {
fmt.Println("键'grape'存在且值不为0")
} else {
fmt.Println("键'grape'不存在或值为0")
}
结构体
type Person struct {
Name string
Age int
Contact struct {
Phone string
Email string
}
}
p1 := Person{Name: "Alice", Age: 25}
p2 := Person{"Bob", 30}
p3 := &Person{Name: "Charlie"}
temp := struct {
X, Y int
}{10, 20}
四、指针与方法(重点:值是否会变化)
指针基础
var a int = 42
var p *int = &a
fmt.Println(*p)
*p = 100
fmt.Println(a)
type Circle struct { Radius float64 }
c := &Circle{Radius: 5}
c.Radius = 10
(*c).Radius = 15
值接收者 vs 指针接收者(关键区别)
type Counter struct {
count int
}
func (c Counter) IncrementByValue() {
c.count++
fmt.Printf("IncrementByValue内部: count = %d\n", c.count)
}
func (c *Counter) IncrementByPointer() {
c.count++
fmt.Printf("IncrementByPointer内部: count = %d\n", c.count)
}
func main() {
counter := Counter{count: 0}
fmt.Printf("初始值: count = %d\n", counter.count)
counter.IncrementByValue()
fmt.Printf("值接收者调用后: count = %d\n", counter.count)
counter.IncrementByPointer()
fmt.Printf("指针接收者调用后: count = %d\n", counter.count)
}
自动转换机制
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14 * c.Radius * c.Radius
}
func (c *Circle) Scale(factor float64) {
c.Radius *= factor
}
func main() {
c1 := Circle{Radius: 5}
c1.Scale(2)
fmt.Printf("c1半径: %.2f\n", c1.Radius)
c2 := &Circle{Radius: 5}
area := c2.Area()
fmt.Printf("c2面积: %.2f\n", area)
}
方法接收者选择原则
五、控制流
if - 条件判断
if age >= 18 {
fmt.Println("成年人")
}
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 {
fmt.Println("良好")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
if err := process(); err != nil {
fmt.Printf("处理出错: %v\n", err)
}
if data != nil {
fmt.Println("数据有效")
}
if x > 0 {
fmt.Println("x是正数")
}
if x > 0 {
fmt.Println("正数")
} else {
fmt.Println("非正数")
}
if x > 0 {
fmt.Println("正数")
} else if x < 0 {
fmt.Println("负数")
} else {
fmt.Println("零")
}
if val, ok := m1["a"]; ok {
fmt.Println("键存在,值为:", val)
} else {
fmt.Println("键不存在")
}
if err := process(); err != nil {
fmt.Printf("处理出错: %v\n", err)
return
}
if x, y := 1, 2; x < y {
fmt.Println("x小于y")
}
if x > 0 {
if y > 0 {
fmt.Println("x和y都是正数")
}
}
if x > 0 && y > 0 {
fmt.Println("x和y都是正数")
}
if x > 0 || y > 0 {
fmt.Println("x或y至少一个是正数")
}
var val interface{} = "hello"
if str, ok := val.(string); ok {
fmt.Println("是字符串:", str)
}
switch - 多分支选择
switch day {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
fmt.Println("工作日")
case "Saturday", "Sunday":
fmt.Println("周末")
default:
fmt.Println("无效日期")
}
switch {
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B")
case score >= 70:
fmt.Println("C")
default:
fmt.Println("D")
}
switch num {
case 1:
fmt.Println("1")
fallthrough
case 2:
fmt.Println("2")
case 3:
fmt.Println("3")
}
for - 循环
for i := 0; i < 10; i++ {
fmt.Println(i)
}
count := 0
for count < 5 {
fmt.Println(count)
count++
}
for {
if condition {
break
}
}
for index, value := range []int{1, 2, 3} {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}
for _, value := range slice {
fmt.Println(value)
}
for key := range map {
fmt.Println(key)
}
break 和 continue
for i := 0; i < 10; i++ {
if i == 5 {
break
}
fmt.Println(i)
}
outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break outer
}
fmt.Printf("(%d,%d) ", i, j)
}
}
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i)
}
六、函数
函数定义
func add(a int, b int) int {
return a + b
}
func multiply(x, y float64) float64 {
return x * y
}
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除零错误")
}
return a / b, nil
}
func getCoordinates() (x int, y int) {
x = 10
y = 20
return
}
func sum(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
defer - 延迟执行
func readFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
return nil
}
func test() {
defer fmt.Println("第一个defer")
defer fmt.Println("第二个defer")
defer fmt.Println("第三个defer")
fmt.Println("函数体")
}
panic 和 recover
func divide(a, b int) int {
if b == 0 {
panic("除数不能为零")
}
return a / b
}
func safeDivide(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("发生错误: %v", r)
result = 0
}
}()
if b == 0 {
panic("除零错误")
}
return a / b, nil
}
func main() {
result, err := safeDivide(10, 0)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果:", result)
}
}
七、接口
接口定义与实现
type Shape interface {
Area() float64
Perimeter() float64
}
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
var s Shape = Rectangle{Width: 3, Height: 4}
area := s.Area()
interface{} vs any(Go 1.18+)
var v1 interface{} = 42
var v2 interface{} = "hello"
var v3 any = 42
var v4 any = "hello"
v1 = v3
v3 = v1
func PrintValue(v interface{}) {
fmt.Println(v)
}
func PrintValueAny(v any) {
fmt.Println(v)
}
var data any = []int{1, 2, 3}
if slice, ok := data.([]int); ok {
fmt.Println("是int切片:", slice)
}
switch v := data.(type) {
case []int:
fmt.Println("int切片,长度:", len(v))
case string:
fmt.Println("字符串:", v)
default:
fmt.Printf("其他类型: %T\n", v)
}
八、并发编程
goroutine(轻量级线程)
func sayHello() {
fmt.Println("Hello from goroutine")
}
func main() {
go sayHello()
fmt.Println("Hello from main")
time.Sleep(100 * time.Millisecond)
}
go func(msg string) {
fmt.Println(msg)
}("Hello from goroutine")
channel(管道)
ch := make(chan int)
ch := make(chan int, 3)
ch <- 42
value := <-ch
close(ch)
value, ok := <-ch
for value := range ch {
fmt.Println(value)
}
func producer(ch chan<- int) {
ch <- 1
}
func consumer(ch <-chan int) {
value := <-ch
}
channel 阻塞机制详解
func main() {
ch := make(chan int)
go func() {
fmt.Println("准备发送数据...")
ch <- 42
fmt.Println("数据已发送")
}()
fmt.Println("准备接收数据...")
value := <-ch
fmt.Println("接收到数据:", value)
}
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
val1 := <-ch
val2 := <-ch
}
func demonstrateBlocking() {
ch := make(chan string)
go func() {
time.Sleep(2 * time.Second)
fmt.Println("goroutine: 准备发送数据")
ch <- "Hello"
fmt.Println("goroutine: 数据已发送")
}()
fmt.Println("main: 准备接收数据(会阻塞2秒)")
value := <-ch
fmt.Println("main: 接收到数据:", value)
}
func nonBlockingExample() {
ch := make(chan int)
select {
case ch <- 42:
fmt.Println("发送成功")
default:
fmt.Println("发送失败(管道满或无接收者)")
}
select {
case value := <-ch:
fmt.Println("接收到:", value)
default:
fmt.Println("没有数据(立即返回,不阻塞)")
}
}
func producerConsumer() {
ch := make(chan int, 3)
go func() {
for i := 1; i <= 5; i++ {
ch <- i
fmt.Printf("生产: %d\n", i)
}
close(ch)
}()
for value := range ch {
fmt.Printf("消费: %d\n", value)
time.Sleep(500 * time.Millisecond)
}
}
select - 多路复用
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch1 <- "来自ch1"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "来自ch2"
}()
select {
case msg1 := <-ch1:
fmt.Println("收到:", msg1)
case msg2 := <-ch2:
fmt.Println("收到:", msg2)
case <-time.After(3 * time.Second):
fmt.Println("超时")
default:
fmt.Println("非阻塞")
}
sync.WaitGroup(等待组)
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("任务%d完成\n", id)
}(i)
}
wg.Wait()
fmt.Println("所有任务完成")
九、时间处理
Timer(单次定时)
timer := time.NewTimer(2 * time.Second)
<-timer.C
fmt.Println("时间到")
if timer.Stop() {
fmt.Println("计时器已停止")
}
Ticker(重复定时)- 正确使用方式
func main() {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
go func() {
for t := range ticker.C {
fmt.Printf("定时触发: %v\n", t.Format("15:04:05.000"))
}
fmt.Println("Ticker停止,goroutine退出")
}()
time.Sleep(3 * time.Second)
fmt.Println("主程序结束,defer ticker.Stop() 将被调用")
}
func wrongUsage() {
ticker := time.NewTicker(1 * time.Second)
go func() {
for t := range ticker.C {
fmt.Println(t)
}
}()
}
func correctUsage() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
go func() {
for t := range ticker.C {
fmt.Println(t)
}
}()
}
时间操作
now := time.Now()
fmt.Println(now.Format("2006-01-02 15:04:05"))
duration := 2 * time.Hour
future := now.Add(duration)
past := now.Add(-duration)
diff := future.Sub(now)
fmt.Println(duration.Seconds())
十、其他重要关键字
type - 类型定义
type Celsius float64
type Fahrenheit float64
type ID string
type IntAlias = int
type Person struct {
Name string
Age int
}
type Reader interface {
Read(p []byte) (n int, err error)
}
type Handler func(string) int
package 和 import
package main
package mylib
import (
"fmt"
"math"
"github.com/user/package"
. "mypackage"
m "math"
_ "database/sql"
)
range - 遍历
for i, v := range []int{1, 2, 3} {
fmt.Printf("索引%d: 值%d\n", i, v)
}
for k, v := range map[string]int{"a": 1, "b": 2} {
fmt.Printf("键%s: 值%d\n", k, v)
}
for i, ch := range "你好" {
fmt.Printf("位置%d: 字符%c\n", i, ch)
}
for value := range ch {
fmt.Println(value)
}
获取对象类型
var x int = 42
var y string = "hello"
var z []int = []int{1, 2, 3}
fmt.Printf("x的类型: %T\n", x)
fmt.Printf("y的类型: %T\n", y)
fmt.Printf("z的类型: %T\n", z)
import "reflect"
var num int = 100
var name string = "Go"
fmt.Println("num的类型:", reflect.TypeOf(num))
fmt.Println("name的类型:", reflect.TypeOf(name))
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 25}
fmt.Printf("p的类型: %T\n", p)
ptr := &Person{Name: "Bob", Age: 30}
fmt.Printf("ptr的类型: %T\n", ptr)
var val interface{} = 42
fmt.Printf("val的类型: %T\n", val)
var data any = "hello"
switch v := data.(type) {
case int:
fmt.Printf("是int类型: %d\n", v)
case string:
fmt.Printf("是string类型: %s\n", v)
default:
fmt.Printf("其他类型: %T\n", v)
}
import "reflect"
t := reflect.TypeOf(42)
fmt.Println("类型名称:", t.Name())
fmt.Println("类型字符串:", t.String())
fmt.Println("类型种类:", t.Kind())
func printType(v interface{}) {
switch v := v.(type) {
case int:
fmt.Printf("整数: %d (类型: %T)\n", v, v)
case string:
fmt.Printf("字符串: %s (类型: %T)\n", v, v)
case []int:
fmt.Printf("int切片: %v (类型: %T)\n", v, v)
default:
fmt.Printf("未知类型: %T, 值: %v\n", v, v)
}
}
printType(42)
printType("hello")
printType([]int{1, 2, 3})
十一、重要特性总结
1. 值类型 vs 引用类型
| 类型 | 值类型 | 引用类型 |
|---|
| 示例 | int, float, bool, string, 数组, 结构体 | 切片, 映射, 管道, 函数, 接口 |
| 赋值 | 复制整个值 | 复制引用(共享底层数据) |
| nil值 | 不能为nil | 可以为nil |
| 修改 | 修改不影响原值 | 修改影响所有引用 |
2. 方法接收者选择原则
- 值接收者:方法不需要修改接收者,或接收者是小型结构体
- 指针接收者:方法需要修改接收者,或接收者是大型结构体(避免复制)
- 一致性:同一类型的多个方法应该使用相同类型的接收者
3. any 使用指南
- Go 1.18+:优先使用
any,更简洁
- 泛型代码:必须使用
any
- 旧代码维护:保持
interface{} 以兼容
- 两者完全等价:编译后没有区别
4. Ticker 最佳实践
func useTicker() {
ticker := time.NewTicker(interval)
defer ticker.Stop()
}
5. 并发安全模式
var wg sync.WaitGroup
for i := 0; i < n; i++ {
wg.Add(1)
go func() {
defer wg.Done()
}()
}
wg.Wait()
results := make(chan Result, n)
for i := 0; i < n; i++ {
go func() {
results <- doWork()
}()
}