# 数据结构
数组
数组基础
数组声明和初始化
package main
import "fmt"
func main() {
// 数组声明的几种方式
var arr1 [5]int // 声明长度为5的整数数组,零值初始化
fmt.Printf("零值数组: %v\n", arr1)
// 声明并初始化
var arr2 = [5]int{1, 2, 3, 4, 5}
fmt.Printf("初始化数组: %v\n", arr2)
// 简短声明
arr3 := [3]string{"Go", "Python", "Java"}
fmt.Printf("字符串数组: %v\n", arr3)
// 让编译器推断长度
arr4 := [...]int{10, 20, 30, 40}
fmt.Printf("推断长度数组: %v,长度: %d\n", arr4, len(arr4))
// 指定索引初始化
arr5 := [5]int{1: 100, 3: 300}
fmt.Printf("指定索引初始化: %v\n", arr5)
// 数组的长度是类型的一部分
fmt.Printf("arr2的类型: %T\n", arr2)
fmt.Printf("arr3的类型: %T\n", arr3)
}
go run array_basic.go
数组操作
package main
import "fmt"
func main() {
// 创建数组
numbers := [5]int{10, 20, 30, 40, 50}
// 访问和修改元素
fmt.Printf("原数组: %v\n", numbers)
fmt.Printf("第一个元素: %d\n", numbers[0])
fmt.Printf("最后一个元素: %d\n", numbers[len(numbers)-1])
// 修改元素
numbers[2] = 999
fmt.Printf("修改后: %v\n", numbers)
// 遍历数组
fmt.Println("\n使用索引遍历:")
for i := 0; i < len(numbers); i++ {
fmt.Printf("索引 %d: 值 %d\n", i, numbers[i])
}
fmt.Println("\n使用range遍历:")
for index, value := range numbers {
fmt.Printf("索引 %d: 值 %d\n", index, value)
}
// 数组比较
arr1 := [3]int{1, 2, 3}
arr2 := [3]int{1, 2, 3}
arr3 := [3]int{1, 2, 4}
fmt.Printf("\narr1 == arr2: %t\n", arr1 == arr2)
fmt.Printf("arr1 == arr3: %t\n", arr1 == arr3)
// 数组复制
original := [3]int{1, 2, 3}
copy := original // 值复制
copy[0] = 999
fmt.Printf("\n原数组: %v\n", original)
fmt.Printf("复制数组: %v\n", copy)
}
go run array_operations.go
多维数组
package main
import "fmt"
func main() {
// 二维数组
var matrix [3][4]int
// 初始化二维数组
matrix = [3][4]int{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
}
fmt.Println("二维数组:")
for i := 0; i < len(matrix); i++ {
for j := 0; j < len(matrix[i]); j++ {
fmt.Printf("%3d ", matrix[i][j])
}
fmt.Println()
}
// 使用range遍历二维数组
fmt.Println("\n使用range遍历:")
for i, row := range matrix {
fmt.Printf("第%d行: ", i+1)
for j, val := range row {
fmt.Printf("[%d,%d]=%d ", i, j, val)
}
fmt.Println()
}
// 三维数组示例
cube := [2][2][2]int{
{
{1, 2},
{3, 4},
},
{
{5, 6},
{7, 8},
},
}
fmt.Println("\n三维数组:")
for i, plane := range cube {
fmt.Printf("平面 %d:\n", i)
for j, row := range plane {
fmt.Printf(" 行 %d: %v\n", j, row)
}
}
}
go run array_multidimensional.go
切片
切片基础
切片声明和创建
package main
import "fmt"
func main() {
// 切片声明
var slice1 []int
fmt.Printf("空切片: %v, 长度: %d, 容量: %d\n", slice1, len(slice1), cap(slice1))
fmt.Printf("是否为nil: %t\n", slice1 == nil)
// 使用make创建切片
slice2 := make([]int, 5) // 长度为5,容量为5
fmt.Printf("make切片: %v, 长度: %d, 容量: %d\n", slice2, len(slice2), cap(slice2))
slice3 := make([]int, 3, 10) // 长度为3,容量为10
fmt.Printf("指定容量: %v, 长度: %d, 容量: %d\n", slice3, len(slice3), cap(slice3))
// 切片字面量
slice4 := []int{1, 2, 3, 4, 5}
fmt.Printf("字面量切片: %v, 长度: %d, 容量: %d\n", slice4, len(slice4), cap(slice4))
// 从数组创建切片
arr := [5]int{10, 20, 30, 40, 50}
slice5 := arr[1:4] // 从索引1到3(不包括4)
fmt.Printf("数组切片: %v, 长度: %d, 容量: %d\n", slice5, len(slice5), cap(slice5))
// 切片的切片
slice6 := slice4[1:3]
fmt.Printf("切片的切片: %v, 长度: %d, 容量: %d\n", slice6, len(slice6), cap(slice6))
}
go run slice_basic.go
切片操作
package main
import "fmt"
func main() {
// 创建切片
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("原切片: %v\n", slice)
// append操作
slice = append(slice, 6)
fmt.Printf("添加一个元素: %v\n", slice)
slice = append(slice, 7, 8, 9)
fmt.Printf("添加多个元素: %v\n", slice)
// 添加另一个切片
other := []int{10, 11, 12}
slice = append(slice, other...)
fmt.Printf("添加切片: %v\n", slice)
// 切片截取
fmt.Printf("\n切片截取操作:\n")
fmt.Printf("slice[2:5]: %v\n", slice[2:5])
fmt.Printf("slice[:3]: %v\n", slice[:3])
fmt.Printf("slice[3:]: %v\n", slice[3:])
fmt.Printf("slice[:]: %v\n", slice[:])
// copy操作
source := []int{1, 2, 3, 4, 5}
dest := make([]int, 3)
n := copy(dest, source)
fmt.Printf("\n复制操作:\n")
fmt.Printf("源切片: %v\n", source)
fmt.Printf("目标切片: %v\n", dest)
fmt.Printf("复制了 %d 个元素\n", n)
// 删除元素(通过切片重组)
numbers := []int{1, 2, 3, 4, 5, 6, 7}
fmt.Printf("\n删除操作:\n")
fmt.Printf("原切片: %v\n", numbers)
// 删除索引2的元素
index := 2
numbers = append(numbers[:index], numbers[index+1:]...)
fmt.Printf("删除索引2后: %v\n", numbers)
}
go run slice_operations.go
切片的内存管理
package main
import "fmt"
func main() {
// 切片的底层数组
arr := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice1 := arr[2:5]
slice2 := arr[3:6]
fmt.Printf("原数组: %v\n", arr)
fmt.Printf("slice1: %v\n", slice1)
fmt.Printf("slice2: %v\n", slice2)
// 修改slice1会影响底层数组和slice2
slice1[1] = 999
fmt.Printf("\n修改slice1[1]后:\n")
fmt.Printf("数组: %v\n", arr)
fmt.Printf("slice1: %v\n", slice1)
fmt.Printf("slice2: %v\n", slice2)
// 切片扩容
fmt.Printf("\n切片扩容示例:\n")
slice := make([]int, 0, 2)
fmt.Printf("初始: len=%d, cap=%d, %v\n", len(slice), cap(slice), slice)
for i := 0; i < 10; i++ {
slice = append(slice, i)
fmt.Printf("添加%d: len=%d, cap=%d, %v\n", i, len(slice), cap(slice), slice)
}
// 演示切片的引用特性
fmt.Printf("\n切片引用特性:\n")
original := []int{1, 2, 3, 4, 5}
reference := original
fmt.Printf("原切片: %v\n", original)
fmt.Printf("引用切片: %v\n", reference)
reference[0] = 999
fmt.Printf("修改引用后:\n")
fmt.Printf("原切片: %v\n", original)
fmt.Printf("引用切片: %v\n", reference)
// 创建独立副本
independent := make([]int, len(original))
copy(independent, original)
independent[1] = 888
fmt.Printf("\n独立副本:\n")
fmt.Printf("原切片: %v\n", original)
fmt.Printf("独立副本: %v\n", independent)
}
go run slice_memory.go
切片的高级应用
切片作为函数参数
package main
import "fmt"
// 修改切片元素
func modifySlice(s []int) {
if len(s) > 0 {
s[0] = 999
}
fmt.Printf("函数内切片: %v\n", s)
}
// 向切片添加元素(错误方式)
func appendWrong(s []int, value int) {
s = append(s, value)
fmt.Printf("函数内添加后: %v\n", s)
}
// 向切片添加元素(正确方式)
func appendCorrect(s []int, value int) []int {
s = append(s, value)
fmt.Printf("函数内添加后: %v\n", s)
return s
}
// 使用指针修改切片
func appendWithPointer(s *[]int, value int) {
*s = append(*s, value)
fmt.Printf("函数内添加后: %v\n", *s)
}
// 过滤切片
func filter(s []int, predicate func(int) bool) []int {
var result []int
for _, v := range s {
if predicate(v) {
result = append(result, v)
}
}
return result
}
// 映射切片
func mapSlice(s []int, fn func(int) int) []int {
result := make([]int, len(s))
for i, v := range s {
result[i] = fn(v)
}
return result
}
func main() {
// 修改切片元素
slice1 := []int{1, 2, 3, 4, 5}
fmt.Printf("调用前: %v\n", slice1)
modifySlice(slice1)
fmt.Printf("调用后: %v\n", slice1)
// 错误的添加方式
fmt.Printf("\n错误的添加方式:\n")
slice2 := []int{1, 2, 3}
fmt.Printf("调用前: %v\n", slice2)
appendWrong(slice2, 4)
fmt.Printf("调用后: %v\n", slice2) // 没有变化
// 正确的添加方式
fmt.Printf("\n正确的添加方式:\n")
slice3 := []int{1, 2, 3}
fmt.Printf("调用前: %v\n", slice3)
slice3 = appendCorrect(slice3, 4)
fmt.Printf("调用后: %v\n", slice3)
// 使用指针
fmt.Printf("\n使用指针:\n")
slice4 := []int{1, 2, 3}
fmt.Printf("调用前: %v\n", slice4)
appendWithPointer(&slice4, 4)
fmt.Printf("调用后: %v\n", slice4)
// 函数式操作
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 过滤偶数
evens := filter(numbers, func(n int) bool { return n%2 == 0 })
fmt.Printf("\n偶数: %v\n", evens)
// 映射为平方
squares := mapSlice(numbers, func(n int) int { return n * n })
fmt.Printf("平方: %v\n", squares)
}
go run slice_functions.go
映射(Map)
映射基础
映射的创建和初始化
package main
import "fmt"
func main() {
// 声明映射
var map1 map[string]int
fmt.Printf("空映射: %v\n", map1)
fmt.Printf("是否为nil: %t\n", map1 == nil)
// 使用make创建映射
map2 := make(map[string]int)
fmt.Printf("make映射: %v\n", map2)
fmt.Printf("是否为nil: %t\n", map2 == nil)
// 映射字面量
map3 := map[string]int{
"apple": 5,
"banana": 3,
"orange": 8,
}
fmt.Printf("字面量映射: %v\n", map3)
// 空映射字面量
map4 := map[string]int{}
fmt.Printf("空字面量映射: %v\n", map4)
// 不同类型的映射
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Charlie": 35,
}
scores := map[string]float64{
"Math": 95.5,
"English": 87.0,
"Science": 92.3,
}
fmt.Printf("年龄映射: %v\n", ages)
fmt.Printf("分数映射: %v\n", scores)
// 复杂类型的映射
students := map[int]map[string]interface{}{
1: {
"name": "Alice",
"age": 20,
"gpa": 3.8,
},
2: {
"name": "Bob",
"age": 22,
"gpa": 3.6,
},
}
fmt.Printf("学生映射: %v\n", students)
}
go run map_basic.go
映射操作
package main
import "fmt"
func main() {
// 创建映射
fruits := map[string]int{
"apple": 5,
"banana": 3,
"orange": 8,
}
fmt.Printf("原映射: %v\n", fruits)
// 访问元素
fmt.Printf("苹果数量: %d\n", fruits["apple"])
fmt.Printf("不存在的键: %d\n", fruits["grape"]) // 返回零值
// 检查键是否存在
value, exists := fruits["banana"]
fmt.Printf("香蕉存在: %t, 数量: %d\n", exists, value)
value, exists = fruits["grape"]
fmt.Printf("葡萄存在: %t, 数量: %d\n", exists, value)
// 添加和修改元素
fruits["grape"] = 12 // 添加新键
fruits["apple"] = 10 // 修改现有键
fmt.Printf("添加和修改后: %v\n", fruits)
// 删除元素
delete(fruits, "banana")
fmt.Printf("删除香蕉后: %v\n", fruits)
// 删除不存在的键(安全操作)
delete(fruits, "watermelon")
fmt.Printf("删除不存在键后: %v\n", fruits)
// 获取映射长度
fmt.Printf("映射长度: %d\n", len(fruits))
// 遍历映射
fmt.Println("\n遍历映射:")
for key, value := range fruits {
fmt.Printf("%s: %d\n", key, value)
}
// 只遍历键
fmt.Println("\n只遍历键:")
for key := range fruits {
fmt.Printf("键: %s\n", key)
}
// 只遍历值
fmt.Println("\n只遍历值:")
for _, value := range fruits {
fmt.Printf("值: %d\n", value)
}
}
go run map_operations.go
映射的高级应用
package main
import (
"fmt"
"sort"
)
func main() {
// 统计字符出现次数
text := "hello world"
charCount := make(map[rune]int)
for _, char := range text {
charCount[char]++
}
fmt.Printf("字符统计: %v\n", charCount)
// 分组操作
students := []struct {
Name string
Grade string
Score int
}{
{"Alice", "A", 95},
{"Bob", "B", 87},
{"Charlie", "A", 92},
{"David", "B", 78},
{"Eve", "A", 88},
}
// 按年级分组
gradeGroups := make(map[string][]string)
for _, student := range students {
gradeGroups[student.Grade] = append(gradeGroups[student.Grade], student.Name)
}
fmt.Printf("\n按年级分组: %v\n", gradeGroups)
// 计算平均分
gradeAverage := make(map[string]float64)
gradeCount := make(map[string]int)
gradeSum := make(map[string]int)
for _, student := range students {
gradeSum[student.Grade] += student.Score
gradeCount[student.Grade]++
}
for grade := range gradeSum {
gradeAverage[grade] = float64(gradeSum[grade]) / float64(gradeCount[grade])
}
fmt.Printf("年级平均分: %v\n", gradeAverage)
// 映射排序(按键排序)
scores := map[string]int{
"Alice": 95,
"Bob": 87,
"Charlie": 92,
"David": 78,
"Eve": 88,
}
// 提取键并排序
var names []string
for name := range scores {
names = append(names, name)
}
sort.Strings(names)
fmt.Printf("\n按姓名排序:\n")
for _, name := range names {
fmt.Printf("%s: %d\n", name, scores[name])
}
// 按值排序
type kv struct {
Key string
Value int
}
var sortedScores []kv
for k, v := range scores {
sortedScores = append(sortedScores, kv{k, v})
}
sort.Slice(sortedScores, func(i, j int) bool {
return sortedScores[i].Value > sortedScores[j].Value
})
fmt.Printf("\n按分数排序:\n")
for _, kv := range sortedScores {
fmt.Printf("%s: %d\n", kv.Key, kv.Value)
}
}
go run map_advanced.go
结构体
结构体基础
结构体定义和初始化
package main
import "fmt"
// 定义结构体
type Person struct {
Name string
Age int
City string
}
// 嵌套结构体
type Address struct {
Street string
City string
ZipCode string
}
type Employee struct {
ID int
Name string
Address Address
Salary float64
}
// 匿名字段
type Student struct {
string // 匿名字段
int // 匿名字段
Grade string
}
func main() {
// 结构体初始化的几种方式
// 1. 零值初始化
var p1 Person
fmt.Printf("零值结构体: %+v\n", p1)
// 2. 字段赋值
p1.Name = "Alice"
p1.Age = 25
p1.City = "New York"
fmt.Printf("赋值后: %+v\n", p1)
// 3. 结构体字面量(按顺序)
p2 := Person{"Bob", 30, "Los Angeles"}
fmt.Printf("按顺序初始化: %+v\n", p2)
// 4. 结构体字面量(指定字段)
p3 := Person{
Name: "Charlie",
Age: 35,
City: "Chicago",
}
fmt.Printf("指定字段初始化: %+v\n", p3)
// 5. 部分字段初始化
p4 := Person{
Name: "David",
Age: 28,
// City字段使用零值
}
fmt.Printf("部分初始化: %+v\n", p4)
// 嵌套结构体
emp := Employee{
ID: 1001,
Name: "John Doe",
Address: Address{
Street: "123 Main St",
City: "Boston",
ZipCode: "02101",
},
Salary: 75000.0,
}
fmt.Printf("\n嵌套结构体: %+v\n", emp)
// 匿名字段
s := Student{
string: "Jane Smith", // 匿名string字段
int: 20, // 匿名int字段
Grade: "A",
}
fmt.Printf("\n匿名字段结构体: %+v\n", s)
fmt.Printf("访问匿名字段: 姓名=%s, 年龄=%d\n", s.string, s.int)
}
go run struct_basic.go
结构体方法
package main
import (
"fmt"
"math"
)
// 定义结构体
type Rectangle struct {
Width float64
Height float64
}
type Circle struct {
Radius float64
}
// 值接收者方法
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// 指针接收者方法
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
func (r *Rectangle) SetDimensions(width, height float64) {
r.Width = width
r.Height = height
}
// Circle的方法
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Circumference() float64 {
return 2 * math.Pi * c.Radius
}
func (c *Circle) SetRadius(radius float64) {
c.Radius = radius
}
// 字符串表示方法
func (r Rectangle) String() string {
return fmt.Sprintf("Rectangle{Width: %.2f, Height: %.2f}", r.Width, r.Height)
}
func (c Circle) String() string {
return fmt.Sprintf("Circle{Radius: %.2f}", c.Radius)
}
func main() {
// 创建矩形
rect := Rectangle{Width: 10, Height: 5}
fmt.Printf("矩形: %s\n", rect)
fmt.Printf("面积: %.2f\n", rect.Area())
fmt.Printf("周长: %.2f\n", rect.Perimeter())
// 使用指针接收者方法
fmt.Printf("\n缩放前: %s\n", rect)
rect.Scale(2.0)
fmt.Printf("缩放后: %s\n", rect)
// 修改尺寸
rect.SetDimensions(8, 6)
fmt.Printf("修改尺寸后: %s\n", rect)
// 创建圆形
circle := Circle{Radius: 3}
fmt.Printf("\n圆形: %s\n", circle)
fmt.Printf("面积: %.2f\n", circle.Area())
fmt.Printf("周长: %.2f\n", circle.Circumference())
// 修改半径
circle.SetRadius(5)
fmt.Printf("修改半径后: %s\n", circle)
fmt.Printf("新面积: %.2f\n", circle.Area())
// 演示值接收者vs指针接收者
fmt.Printf("\n值接收者vs指针接收者:\n")
rect2 := Rectangle{Width: 4, Height: 3}
fmt.Printf("原始矩形: %s\n", rect2)
// 值接收者不会修改原始值
area := rect2.Area() // 值接收者
fmt.Printf("计算面积后: %s (面积: %.2f)\n", rect2, area)
// 指针接收者会修改原始值
rect2.Scale(1.5) // 指针接收者
fmt.Printf("缩放后: %s\n", rect2)
}
go run struct_methods.go
结构体嵌入和组合
package main
import "fmt"
// 基础结构体
type Animal struct {
Name string
Age int
}
func (a Animal) Speak() string {
return fmt.Sprintf("%s makes a sound", a.Name)
}
func (a Animal) Info() string {
return fmt.Sprintf("%s is %d years old", a.Name, a.Age)
}
// 嵌入Animal的结构体
type Dog struct {
Animal // 嵌入
Breed string
}
// Dog特有的方法
func (d Dog) Bark() string {
return fmt.Sprintf("%s barks: Woof!", d.Name)
}
// 重写嵌入类型的方法
func (d Dog) Speak() string {
return fmt.Sprintf("%s barks", d.Name)
}
type Cat struct {
Animal
IndoorOnly bool
}
func (c Cat) Meow() string {
return fmt.Sprintf("%s meows: Meow!", c.Name)
}
func (c Cat) Speak() string {
return fmt.Sprintf("%s meows", c.Name)
}
// 多重嵌入
type Engine struct {
Power int
Type string
}
func (e Engine) Start() string {
return fmt.Sprintf("Engine started: %d HP %s", e.Power, e.Type)
}
type GPS struct {
Brand string
}
func (g GPS) Navigate() string {
return fmt.Sprintf("Navigating with %s GPS", g.Brand)
}
type Car struct {
Engine
GPS
Brand string
Model string
}
func (c Car) Drive() string {
return fmt.Sprintf("Driving %s %s", c.Brand, c.Model)
}
func main() {
// 创建Dog实例
dog := Dog{
Animal: Animal{
Name: "Buddy",
Age: 3,
},
Breed: "Golden Retriever",
}
fmt.Printf("狗的信息: %+v\n", dog)
fmt.Printf("基本信息: %s\n", dog.Info()) // 继承的方法
fmt.Printf("叫声: %s\n", dog.Speak()) // 重写的方法
fmt.Printf("吠叫: %s\n", dog.Bark()) // 特有方法
fmt.Printf("直接访问名字: %s\n", dog.Name) // 直接访问嵌入字段
// 创建Cat实例
cat := Cat{
Animal: Animal{
Name: "Whiskers",
Age: 2,
},
IndoorOnly: true,
}
fmt.Printf("\n猫的信息: %+v\n", cat)
fmt.Printf("基本信息: %s\n", cat.Info())
fmt.Printf("叫声: %s\n", cat.Speak())
fmt.Printf("喵叫: %s\n", cat.Meow())
// 多重嵌入示例
car := Car{
Engine: Engine{
Power: 300,
Type: "V6",
},
GPS: GPS{
Brand: "Garmin",
},
Brand: "Toyota",
Model: "Camry",
}
fmt.Printf("\n汽车信息: %+v\n", car)
fmt.Printf("启动引擎: %s\n", car.Start()) // Engine的方法
fmt.Printf("导航: %s\n", car.Navigate()) // GPS的方法
fmt.Printf("驾驶: %s\n", car.Drive()) // Car的方法
// 访问嵌入字段
fmt.Printf("引擎功率: %d HP\n", car.Power) // 直接访问Engine.Power
fmt.Printf("GPS品牌: %s\n", car.GPS.Brand) // 通过类型名访问
// 类型断言和接口
animals := []Animal{dog.Animal, cat.Animal}
fmt.Printf("\n动物列表:\n")
for i, animal := range animals {
fmt.Printf("%d. %s\n", i+1, animal.Speak())
}
}
go run struct_embedding.go
结构体标签和反射
结构体标签
package main
import (
"encoding/json"
"fmt"
"reflect"
)
// 带标签的结构体
type User struct {
ID int `json:"id" db:"user_id" validate:"required"`
Name string `json:"name" db:"full_name" validate:"required,min=2"`
Email string `json:"email" db:"email_address" validate:"required,email"`
Age int `json:"age" db:"age" validate:"min=0,max=120"`
Password string `json:"-" db:"password_hash"` // json:"-" 表示不序列化
IsActive bool `json:"is_active" db:"active"`
}
// 自定义标签
type Product struct {
Name string `form:"name" binding:"required"`
Price float64 `form:"price" binding:"required,gt=0"`
Description string `form:"description"`
Category string `form:"category" binding:"required"`
}
// 读取结构体标签
func printStructTags(v interface{}) {
t := reflect.TypeOf(v)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
fmt.Printf("结构体 %s 的标签信息:\n", t.Name())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("字段: %s\n", field.Name)
if jsonTag := field.Tag.Get("json"); jsonTag != "" {
fmt.Printf(" json: %s\n", jsonTag)
}
if dbTag := field.Tag.Get("db"); dbTag != "" {
fmt.Printf(" db: %s\n", dbTag)
}
if validateTag := field.Tag.Get("validate"); validateTag != "" {
fmt.Printf(" validate: %s\n", validateTag)
}
fmt.Println()
}
}
func main() {
// 创建用户实例
user := User{
ID: 1,
Name: "Alice Johnson",
Email: "alice@example.com",
Age: 28,
Password: "secret123",
IsActive: true,
}
// JSON序列化
jsonData, err := json.MarshalIndent(user, "", " ")
if err != nil {
fmt.Printf("JSON序列化错误: %v\n", err)
return
}
fmt.Printf("JSON序列化结果:\n%s\n\n", jsonData)
// JSON反序列化
jsonStr := `{
"id": 2,
"name": "Bob Smith",
"email": "bob@example.com",
"age": 32,
"is_active": false
}`
var newUser User
err = json.Unmarshal([]byte(jsonStr), &newUser)
if err != nil {
fmt.Printf("JSON反序列化错误: %v\n", err)
return
}
fmt.Printf("反序列化结果: %+v\n\n", newUser)
// 打印结构体标签
printStructTags(user)
// 产品示例
product := Product{
Name: "Laptop",
Price: 999.99,
Description: "High-performance laptop",
Category: "Electronics",
}
fmt.Printf("产品信息: %+v\n\n", product)
printStructTags(product)
}
go run struct_tags.go
接口
接口基础
接口定义和实现
package main
import (
"fmt"
"math"
)
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
// 另一个接口
type Drawable interface {
Draw() string
}
// 组合接口
type DrawableShape interface {
Shape
Drawable
}
// 实现Shape接口的结构体
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)
}
func (r Rectangle) Draw() string {
return fmt.Sprintf("Drawing a rectangle %.1fx%.1f", r.Width, r.Height)
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
func (c Circle) Draw() string {
return fmt.Sprintf("Drawing a circle with radius %.1f", c.Radius)
}
type Triangle struct {
A, B, C float64
}
func (t Triangle) Area() float64 {
// 使用海伦公式
s := (t.A + t.B + t.C) / 2
return math.Sqrt(s * (s - t.A) * (s - t.B) * (s - t.C))
}
func (t Triangle) Perimeter() float64 {
return t.A + t.B + t.C
}
func (t Triangle) Draw() string {
return fmt.Sprintf("Drawing a triangle with sides %.1f, %.1f, %.1f", t.A, t.B, t.C)
}
// 使用接口的函数
func printShapeInfo(s Shape) {
fmt.Printf("面积: %.2f\n", s.Area())
fmt.Printf("周长: %.2f\n", s.Perimeter())
}
func drawShape(d Drawable) {
fmt.Println(d.Draw())
}
func processDrawableShape(ds DrawableShape) {
fmt.Println(ds.Draw())
fmt.Printf("面积: %.2f, 周长: %.2f\n", ds.Area(), ds.Perimeter())
}
func main() {
// 创建不同的形状
rect := Rectangle{Width: 10, Height: 5}
circle := Circle{Radius: 3}
triangle := Triangle{A: 3, B: 4, C: 5}
// 使用Shape接口
shapes := []Shape{rect, circle, triangle}
fmt.Println("所有形状的信息:")
for i, shape := range shapes {
fmt.Printf("\n形状 %d:\n", i+1)
printShapeInfo(shape)
}
// 使用Drawable接口
fmt.Println("\n绘制所有形状:")
drawables := []Drawable{rect, circle, triangle}
for _, drawable := range drawables {
drawShape(drawable)
}
// 使用组合接口
fmt.Println("\n使用组合接口:")
drawableShapes := []DrawableShape{rect, circle, triangle}
for i, ds := range drawableShapes {
fmt.Printf("\n形状 %d:\n", i+1)
processDrawableShape(ds)
}
// 接口类型断言
fmt.Println("\n类型断言示例:")
var s Shape = rect
if r, ok := s.(Rectangle); ok {
fmt.Printf("这是一个矩形,宽度: %.1f, 高度: %.1f\n", r.Width, r.Height)
}
// switch类型断言
fmt.Println("\nswitch类型断言:")
for _, shape := range shapes {
switch v := shape.(type) {
case Rectangle:
fmt.Printf("矩形: %.1f x %.1f\n", v.Width, v.Height)
case Circle:
fmt.Printf("圆形: 半径 %.1f\n", v.Radius)
case Triangle:
fmt.Printf("三角形: 边长 %.1f, %.1f, %.1f\n", v.A, v.B, v.C)
default:
fmt.Printf("未知形状: %T\n", v)
}
}
}
go run interface_basic.go
空接口和类型断言
package main
import "fmt"
// 空接口可以存储任何类型的值
func describe(i interface{}) {
fmt.Printf("值: %v, 类型: %T\n", i, i)
}
// 类型断言函数
func processValue(value interface{}) {
switch v := value.(type) {
case int:
fmt.Printf("整数: %d, 平方: %d\n", v, v*v)
case string:
fmt.Printf("字符串: %s, 长度: %d\n", v, len(v))
case bool:
fmt.Printf("布尔值: %t\n", v)
case []int:
fmt.Printf("整数切片: %v, 长度: %d\n", v, len(v))
case map[string]int:
fmt.Printf("字符串到整数的映射: %v\n", v)
case nil:
fmt.Println("nil值")
default:
fmt.Printf("未知类型: %T, 值: %v\n", v, v)
}
}
// 安全的类型断言
func safeTypeAssertion(value interface{}) {
// 检查是否为字符串
if str, ok := value.(string); ok {
fmt.Printf("安全断言成功 - 字符串: %s\n", str)
} else {
fmt.Printf("不是字符串类型,实际类型: %T\n", value)
}
// 检查是否为整数
if num, ok := value.(int); ok {
fmt.Printf("安全断言成功 - 整数: %d\n", num)
} else {
fmt.Printf("不是整数类型,实际类型: %T\n", value)
}
}
// 通用打印函数
func printAll(values ...interface{}) {
fmt.Println("打印所有值:")
for i, value := range values {
fmt.Printf(" [%d] ", i)
describe(value)
}
}
// 通用比较函数
func compare(a, b interface{}) bool {
return a == b
}
func main() {
// 空接口示例
var empty interface{}
fmt.Println("空接口示例:")
describe(empty) // nil
empty = 42
describe(empty)
empty = "Hello, World!"
describe(empty)
empty = []int{1, 2, 3, 4, 5}
describe(empty)
empty = map[string]int{"apple": 5, "banana": 3}
describe(empty)
// 类型断言示例
fmt.Println("\n类型断言示例:")
values := []interface{}{
42,
"Hello",
true,
[]int{1, 2, 3},
map[string]int{"key": 100},
nil,
3.14,
struct{ Name string }{"Test"},
}
for i, value := range values {
fmt.Printf("\n值 %d: ", i+1)
processValue(value)
}
// 安全类型断言
fmt.Println("\n安全类型断言:")
testValues := []interface{}{"hello", 123, 3.14}
for _, value := range testValues {
fmt.Printf("\n测试值: %v\n", value)
safeTypeAssertion(value)
}
// 通用函数示例
fmt.Println("\n通用函数示例:")
printAll(1, "hello", true, []int{1, 2}, map[string]int{"a": 1})
// 比较示例
fmt.Println("\n比较示例:")
fmt.Printf("42 == 42: %t\n", compare(42, 42))
fmt.Printf("42 == \"42\": %t\n", compare(42, "42"))
fmt.Printf("\"hello\" == \"hello\": %t\n", compare("hello", "hello"))
// 接口切片
fmt.Println("\n接口切片:")
mixed := []interface{}{1, "two", 3.0, true}
for i, item := range mixed {
fmt.Printf("索引 %d: ", i)
describe(item)
}
// 接口映射
fmt.Println("\n接口映射:")
data := map[string]interface{}{
"name": "Alice",
"age": 30,
"active": true,
"scores": []int{95, 87, 92},
"address": map[string]string{"city": "New York", "zip": "10001"},
}
for key, value := range data {
fmt.Printf("%s: ", key)
describe(value)
}
}
go run interface_empty.go
恭喜!你已经掌握了Go语言的主要数据结构。接下来让我们学习Go语言最强大的特性之一:并发编程,包括goroutine和channel的使用。