Golang 结构体与接口
结构体(Struct)
结构体定义与初始化
go
package main
import "fmt"
// 定义结构体
type Person struct {
Name string
Age int
Email string
Address string
}
// 嵌套结构体
type Contact struct {
Phone string
Email string
Wechat string
}
type Employee struct {
ID int
Name string
Contact Contact
Salary float64
}
func structBasicDemo() {
// 方式1:字段名初始化
person1 := Person{
Name: "张三",
Age: 25,
Email: "zhangsan@example.com",
Address: "北京",
}
// 方式2:按顺序初始化
person2 := Person{"李四", 30, "lisi@example.com", "上海"}
// 方式3:部分字段初始化(其他为零值)
person3 := Person{Name: "王五", Age: 28}
// 方式4:使用 new(返回指针)
person4 := new(Person)
person4.Name = "赵六"
person4.Age = 35
fmt.Printf("person1: %+v\n", person1)
fmt.Printf("person2: %+v\n", person2)
fmt.Printf("person3: %+v\n", person3)
fmt.Printf("person4: %+v\n", *person4)
// 嵌套结构体
emp := Employee{
ID: 1001,
Name: "Jackson",
Contact: Contact{
Phone: "13800138000",
Email: "jackson@example.com",
Wechat: "jackson_wx",
},
Salary: 50000,
}
fmt.Printf("\n员工信息: %+v\n", emp)
fmt.Printf("联系电话: %s\n", emp.Contact.Phone)
}匿名结构体
go
func anonymousStructDemo() {
// 定义并初始化匿名结构体
student := struct {
Name string
Grade int
Score float64
}{
Name: "小明",
Grade: 3,
Score: 95.5,
}
fmt.Printf("学生信息: %+v\n", student)
// 匿名结构体切片
students := []struct {
Name string
Score int
}{
{"张三", 85},
{"李四", 90},
{"王五", 88},
}
fmt.Println("\n学生成绩:")
for _, s := range students {
fmt.Printf("%s: %d分\n", s.Name, s.Score)
}
}结构体方法
go
type Rectangle struct {
Width float64
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) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
func (r *Rectangle) SetDimensions(width, height float64) {
r.Width = width
r.Height = height
}
func structMethodDemo() {
rect := Rectangle{Width: 10, Height: 5}
fmt.Printf("原始尺寸: %.2f × %.2f\n", rect.Width, rect.Height)
fmt.Printf("面积: %.2f\n", rect.Area())
fmt.Printf("周长: %.2f\n", rect.Perimeter())
// 修改结构体
rect.Scale(2)
fmt.Printf("\n放大2倍后: %.2f × %.2f\n", rect.Width, rect.Height)
fmt.Printf("面积: %.2f\n", rect.Area())
rect.SetDimensions(15, 8)
fmt.Printf("\n设置新尺寸: %.2f × %.2f\n", rect.Width, rect.Height)
}结构体嵌入(组合)
go
// 基础结构体
type Animal struct {
Name string
Age int
Weight float64
}
func (a Animal) Eat() {
fmt.Printf("%s 正在吃东西\n", a.Name)
}
func (a Animal) Sleep() {
fmt.Printf("%s 正在睡觉\n", a.Name)
}
// 嵌入 Animal
type Dog struct {
Animal // 匿名字段(嵌入)
Breed string
}
func (d Dog) Bark() {
fmt.Printf("%s 正在叫: 汪汪汪!\n", d.Name)
}
type Cat struct {
Animal
Color string
}
func (c Cat) Meow() {
fmt.Printf("%s 正在叫: 喵喵喵!\n", c.Name)
}
func structEmbeddingDemo() {
// 创建 Dog 实例
dog := Dog{
Animal: Animal{
Name: "旺财",
Age: 3,
Weight: 15.5,
},
Breed: "金毛",
}
// 可以直接访问嵌入结构体的字段
fmt.Printf("狗的名字: %s\n", dog.Name)
fmt.Printf("狗的品种: %s\n", dog.Breed)
// 调用嵌入结构体的方法
dog.Eat()
dog.Sleep()
dog.Bark()
// 创建 Cat 实例
fmt.Println()
cat := Cat{
Animal: Animal{Name: "咪咪", Age: 2, Weight: 4.5},
Color: "白色",
}
fmt.Printf("猫的名字: %s, 颜色: %s\n", cat.Name, cat.Color)
cat.Eat()
cat.Meow()
}结构体标签(Tag)
go
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"-"` // 忽略此字段
Age int `json:"age,omitempty"` // 为空时忽略
}
func structTagDemo() {
user := User{
ID: 1,
Username: "jackson",
Email: "jackson@example.com",
Password: "secret123",
Age: 25,
}
// 序列化为 JSON
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("JSON 序列化错误:", err)
return
}
fmt.Println("JSON 数据:", string(jsonData))
// 反序列化
jsonStr := `{"id":2,"username":"alice","email":"alice@example.com","age":30}`
var newUser User
err = json.Unmarshal([]byte(jsonStr), &newUser)
if err != nil {
fmt.Println("JSON 反序列化错误:", err)
return
}
fmt.Printf("反序列化用户: %+v\n", newUser)
}接口(Interface)
接口定义与实现
go
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
// 矩形实现 Shape 接口
type Rect struct {
Width float64
Height float64
}
func (r Rect) Area() float64 {
return r.Width * r.Height
}
func (r Rect) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// 圆形实现 Shape 接口
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * 3.14159 * c.Radius
}
// 使用接口
func printShapeInfo(s Shape) {
fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}
func interfaceBasicDemo() {
rect := Rect{Width: 10, Height: 5}
circle := Circle{Radius: 7}
fmt.Println("矩形信息:")
printShapeInfo(rect)
fmt.Println("\n圆形信息:")
printShapeInfo(circle)
// 接口切片
shapes := []Shape{
Rect{Width: 5, Height: 3},
Circle{Radius: 4},
Rect{Width: 8, Height: 6},
}
fmt.Println("\n所有图形:")
for i, shape := range shapes {
fmt.Printf("图形 %d - ", i+1)
printShapeInfo(shape)
}
}空接口
go
func emptyInterfaceDemo() {
// 空接口可以存储任何类型
var any interface{}
any = 42
fmt.Printf("int: %v\n", any)
any = "Hello"
fmt.Printf("string: %v\n", any)
any = true
fmt.Printf("bool: %v\n", any)
any = []int{1, 2, 3}
fmt.Printf("slice: %v\n", any)
// 空接口切片
data := []interface{}{
"Jackson",
25,
true,
3.14,
[]int{1, 2, 3},
}
fmt.Println("\n空接口切片:")
for i, v := range data {
fmt.Printf("%d: %v (类型: %T)\n", i, v, v)
}
}类型断言
go
func typeAssertionDemo() {
var i interface{} = "Hello, World"
// 类型断言(不安全)
// s := i.(string)
// fmt.Println(s)
// 类型断言(安全)
s, ok := i.(string)
if ok {
fmt.Printf("字符串值: %s\n", s)
} else {
fmt.Println("不是字符串类型")
}
// 尝试错误的类型断言
n, ok := i.(int)
if ok {
fmt.Printf("整数值: %d\n", n)
} else {
fmt.Println("不是整数类型")
}
}类型选择(Type Switch)
go
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: %s (长度: %d)\n", v, len(v))
case bool:
fmt.Printf("布尔值: %t\n", v)
case float64:
fmt.Printf("浮点数: %.2f\n", v)
case []int:
fmt.Printf("整数切片: %v\n", v)
case Person:
fmt.Printf("Person 结构体: %+v\n", v)
case nil:
fmt.Println("nil 值")
default:
fmt.Printf("未知类型: %T\n", v)
}
}
func typeSwitchDemo() {
describe(42)
describe("Hello")
describe(true)
describe(3.14)
describe([]int{1, 2, 3})
describe(Person{Name: "Jackson", Age: 25})
describe(nil)
}接口嵌套
go
// 基础接口
type Reader interface {
Read() string
}
type Writer interface {
Write(data string)
}
// 嵌套接口
type ReadWriter interface {
Reader
Writer
}
// 实现 ReadWriter 接口
type File struct {
Name string
Content string
}
func (f *File) Read() string {
return f.Content
}
func (f *File) Write(data string) {
f.Content = data
}
func interfaceEmbeddingDemo() {
file := &File{Name: "test.txt"}
// File 实现了 ReadWriter 接口
var rw ReadWriter = file
rw.Write("Hello, Golang!")
fmt.Printf("文件内容: %s\n", rw.Read())
// 也可以作为单独的接口使用
var r Reader = file
fmt.Printf("读取内容: %s\n", r.Read())
var w Writer = file
w.Write("Updated content")
fmt.Printf("更新后内容: %s\n", file.Read())
}接口的实际应用
go
// 定义数据库接口
type Database interface {
Connect() error
Query(sql string) ([]map[string]interface{}, error)
Close() error
}
// MySQL 实现
type MySQL struct {
Host string
Port int
}
func (m *MySQL) Connect() error {
fmt.Printf("连接到 MySQL: %s:%d\n", m.Host, m.Port)
return nil
}
func (m *MySQL) Query(sql string) ([]map[string]interface{}, error) {
fmt.Printf("MySQL 执行查询: %s\n", sql)
return []map[string]interface{}{
{"id": 1, "name": "张三"},
{"id": 2, "name": "李四"},
}, nil
}
func (m *MySQL) Close() error {
fmt.Println("关闭 MySQL 连接")
return nil
}
// PostgreSQL 实现
type PostgreSQL struct {
Host string
Port int
}
func (p *PostgreSQL) Connect() error {
fmt.Printf("连接到 PostgreSQL: %s:%d\n", p.Host, p.Port)
return nil
}
func (p *PostgreSQL) Query(sql string) ([]map[string]interface{}, error) {
fmt.Printf("PostgreSQL 执行查询: %s\n", sql)
return []map[string]interface{}{
{"id": 1, "name": "王五"},
}, nil
}
func (p *PostgreSQL) Close() error {
fmt.Println("关闭 PostgreSQL 连接")
return nil
}
// 使用接口的函数
func executeQuery(db Database, sql string) {
db.Connect()
defer db.Close()
results, err := db.Query(sql)
if err != nil {
fmt.Println("查询错误:", err)
return
}
fmt.Println("查询结果:", results)
}
func interfaceApplicationDemo() {
mysql := &MySQL{Host: "localhost", Port: 3306}
postgresql := &PostgreSQL{Host: "localhost", Port: 5432}
fmt.Println("=== MySQL 查询 ===")
executeQuery(mysql, "SELECT * FROM users")
fmt.Println("\n=== PostgreSQL 查询 ===")
executeQuery(postgresql, "SELECT * FROM users")
}完整示例:图书管理系统
go
package main
import "fmt"
// 图书接口
type Book interface {
GetInfo() string
GetPrice() float64
}
// 纸质书
type PaperBook struct {
Title string
Author string
Price float64
PageCount int
}
func (p PaperBook) GetInfo() string {
return fmt.Sprintf("《%s》- %s (纸质书, %d页)", p.Title, p.Author, p.PageCount)
}
func (p PaperBook) GetPrice() float64 {
return p.Price
}
// 电子书
type EBook struct {
Title string
Author string
Price float64
FileSize float64 // MB
}
func (e EBook) GetInfo() string {
return fmt.Sprintf("《%s》- %s (电子书, %.2fMB)", e.Title, e.Author, e.FileSize)
}
func (e EBook) GetPrice() float64 {
return e.Price
}
// 图书馆
type Library struct {
Name string
Books []Book
}
func (l *Library) AddBook(book Book) {
l.Books = append(l.Books, book)
fmt.Printf("已添加: %s\n", book.GetInfo())
}
func (l *Library) ListBooks() {
fmt.Printf("\n=== %s 图书列表 ===\n", l.Name)
totalPrice := 0.0
for i, book := range l.Books {
fmt.Printf("%d. %s - ¥%.2f\n", i+1, book.GetInfo(), book.GetPrice())
totalPrice += book.GetPrice()
}
fmt.Printf("\n总价值: ¥%.2f\n", totalPrice)
}
func main() {
library := &Library{Name: "Jackson图书馆"}
// 添加纸质书
library.AddBook(PaperBook{
Title: "Go语言编程",
Author: "张三",
Price: 89.00,
PageCount: 500,
})
library.AddBook(PaperBook{
Title: "算法导论",
Author: "李四",
Price: 128.00,
PageCount: 800,
})
// 添加电子书
library.AddBook(EBook{
Title: "深入理解计算机系统",
Author: "王五",
Price: 68.00,
FileSize: 15.5,
})
library.AddBook(EBook{
Title: "设计模式",
Author: "赵六",
Price: 45.00,
FileSize: 8.2,
})
// 列出所有图书
library.ListBooks()
}小结
- 结构体:自定义复合数据类型
- 结构体方法:值接收者 vs 指针接收者
- 结构体嵌入:实现组合和代码复用
- 结构体标签:用于序列化、验证等
- 接口:定义行为规范,实现多态
- 空接口:可以存储任何类型
- 类型断言:从接口获取具体类型
- 类型选择:根据类型执行不同逻辑
- 接口嵌套:组合多个接口
- 面向接口编程:提高代码灵活性和可测试性