在传统的面向对象语言中,类是封装数据和行为的核心概念。Go语言选择了不同的道路——它没有类,而是使用结构体(struct)来组织数据,使用方法(method)来定义行为。
// 基本结构体定义
type Person struct {
Name string
Age int
City string
}
// 使用结构体
func main() {
// 创建结构体实例
person := Person{
Name: "Alice",
Age: 30,
City: "Beijing",
}
fmt.Printf("姓名: %s, 年龄: %d, 城市: %s
",
person.Name, person.Age, person.City)
}
结构体的初始化:
// 多种初始化方式
func structInitialization() {
// 1. 零值初始化
var p1 Person
fmt.Printf("零值: %+v
", p1) // {Name: Age:0 City:}
// 2. 字面量初始化
p2 := Person{
Name: "Bob",
Age: 25,
City: "Shanghai",
}
// 3. 部分字段初始化
p3 := Person{
Name: "Charlie",
// Age和City使用零值
}
// 4. 使用new函数
p4 := new(Person)
p4.Name = "David"
p4.Age = 35
// 5. 匿名结构体
p5 := struct {
Name string
Age int
}{
Name: "Eve",
Age: 28,
}
fmt.Printf("p2: %+v
", p2)
fmt.Printf("p3: %+v
", p3)
fmt.Printf("p4: %+v
", p4)
fmt.Printf("p5: %+v
", p5)
}
方法的定义:
值接收者方法:
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 main() {
rect := Rectangle{Width: 10, Height: 5}
fmt.Printf("面积: %.2f
", rect.Area()) // 50.00
fmt.Printf("周长: %.2f
", rect.Perimeter()) // 30.00
}
指针接收者方法:
type Counter struct {
value int
}
// 指针接收者方法 - 可以修改结构体
func (c *Counter) Increment() {
c.value++
}
func (c *Counter) Decrement() {
c.value--
}
func (c *Counter) Value() int {
return c.value
}
// 使用示例
func main() {
counter := &Counter{value: 0}
counter.Increment()
counter.Increment()
counter.Decrement()
fmt.Printf("当前值: %d
", counter.Value()) // 1
}
值接收者 vs 指针接收者
何时使用值接收者
type Point struct {
X, Y float64
}
// 值接收者 - 不修改结构体,且结构体较小
func (p Point) Distance() float64 {
return math.Sqrt(p.X*p.X + p.Y*p.Y)
}
func (p Point) String() string {
return fmt.Sprintf("(%v, %v)", p.X, p.Y)
}
// 使用示例
func main() {
p := Point{3, 4}
fmt.Printf("点: %s, 距离: %.2f
", p, p.Distance())
}
何时使用指针接收者
type BankAccount struct {
balance float64
owner string
}
// 指针接收者 - 需要修改结构体
func (ba *BankAccount) Deposit(amount float64) {
ba.balance += amount
}
func (ba *BankAccount) Withdraw(amount float64) error {
if amount > ba.balance {
return errors.New("余额不足")
}
ba.balance -= amount
return nil
}
func (ba *BankAccount) Balance() float64 {
return ba.balance
}
// 使用示例
func main() {
account := &BankAccount{balance: 1000, owner: "Alice"}
account.Deposit(500)
fmt.Printf("存款后余额: %.2f
", account.Balance())
err := account.Withdraw(200)
if err != nil {
fmt.Println("取款失败:", err)
} else {
fmt.Printf("取款后余额: %.2f
", account.Balance())
}
}
方法集
方法集规则
type T struct {
value int
}
// 值接收者方法
func (t T) ValueMethod() {
fmt.Println("值方法")
}
// 指针接收者方法
func (t *T) PointerMethod() {
fmt.Println("指针方法")
}
func methodSetDemo() {
var t T
var pt *T = &t
// 值类型的方法集
t.ValueMethod() // 可以调用
t.PointerMethod() // 可以调用(Go自动转换)
// 指针类型的方法集
pt.ValueMethod() // 可以调用(Go自动解引用)
pt.PointerMethod() // 可以调用
}
结构体嵌入
匿名字段
// 基础结构体
type Address struct {
Street string
City string
Zip string
}
// 嵌入结构体
type Person struct {
Name string
Age int
Address // 匿名字段
}
// 使用示例
func main() {
person := Person{
Name: "Alice",
Age: 30,
Address: Address{
Street: "123 Main St",
City: "Beijing",
Zip: "100000",
},
}
// 直接访问嵌入字段
fmt.Printf("姓名: %s
", person.Name)
fmt.Printf("街道: %s
", person.Street) // 直接访问
fmt.Printf("城市: %s
", person.City) // 直接访问
// 也可以显式访问
fmt.Printf("邮编: %s
", person.Address.Zip)
}
方法提升
// 基础结构体
type Engine struct {
power int
}
func (e Engine) Start() {
fmt.Printf("引擎启动,功率: %d
", e.power)
}
func (e Engine) Stop() {
fmt.Println("引擎停止")
}
// 嵌入结构体
type Car struct {
Brand string
Engine // 嵌入Engine
}
// 使用示例
func main() {
car := Car{
Brand: "Toyota",
Engine: Engine{power: 200},
}
// 直接调用嵌入结构体的方法
car.Start() // 引擎启动,功率: 200
car.Stop() // 引擎停止
}
接口实现
隐式接口实现
// 定义接口
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)
}
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 printShapeInfo(s Shape) {
fmt.Printf("面积: %.2f, 周长: %.2f
", s.Area(), s.Perimeter())
}
func main() {
shapes := []Shape{
Rectangle{Width: 10, Height: 5},
Circle{Radius: 3},
}
for _, shape := range shapes {
printShapeInfo(shape)
}
}
结构体标签
结构体标签的使用
import (
"encoding/json"
"fmt"
)
type User struct {
ID int `json:"id" db:"user_id"`
Name string `json:"name" db:"user_name"`
Email string `json:"email" db:"user_email"`
Password string `json:"-" db:"user_password"` // 不序列化
}
func structTagsDemo() {
user := User{
ID: 1,
Name: "Alice",
Email: "alice@example.com",
Password: "secret123",
}
// JSON序列化
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("序列化失败:", err)
return
}
fmt.Printf("JSON: %s
", jsonData)
// 输出: {"id":1,"name":"Alice","email":"alice@example.com"}
}
自定义标签处理
import (
"reflect"
"strings"
)
// 自定义标签处理函数
func processStructTags(v interface{}) {
t := reflect.TypeOf(v)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag
// 处理json标签
if jsonTag := tag.Get("json"); jsonTag != "" {
fmt.Printf("字段 %s 的JSON标签: %s
", field.Name, jsonTag)
}
// 处理db标签
if dbTag := tag.Get("db"); dbTag != "" {
fmt.Printf("字段 %s 的DB标签: %s
", field.Name, dbTag)
}
}
}
func main() {
user := User{}
processStructTags(user)
}
结构体的比较
可比较的结构体
type Point struct {
X, Y int
}
func comparableStructs() {
p1 := Point{1, 2}
p2 := Point{1, 2}
p3 := Point{2, 3}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
// 可以作为map的key
points := make(map[Point]string)
points[p1] = "第一个点"
points[p2] = "第二个点"
fmt.Println(points) // map[{1 2}:第二个点]
}
不可比较的结构体
type Person struct {
Name string
Age int
// 包含不可比较的字段
Hobbies []string // 切片不可比较
}
func nonComparableStructs() {
p1 := Person{Name: "Alice", Age: 30, Hobbies: []string{"reading"}}
p2 := Person{Name: "Alice", Age: 30, Hobbies: []string{"reading"}}
// 编译错误:无法比较包含切片的结构体
// fmt.Println(p1 == p2)
// 需要自定义比较函数
fmt.Println(comparePersons(p1, p2))
}
func comparePersons(p1, p2 Person) bool {
if p1.Name != p2.Name || p1.Age != p2.Age {
return false
}
if len(p1.Hobbies) != len(p2.Hobbies) {
return false
}
for i, hobby := range p1.Hobbies {
if hobby != p2.Hobbies[i] {
return false
}
}
return true
}
结构体的内存布局
内存对齐
import "unsafe"
type AlignedStruct struct {
a bool // 1字节
b int64 // 8字节
c bool // 1字节
}
type OptimizedStruct struct {
b int64 // 8字节
a bool // 1字节
c bool // 1字节
}
func memoryLayout() {
fmt.Printf("AlignedStruct大小: %d字节
", unsafe.Sizeof(AlignedStruct{})) // 24字节
fmt.Printf("OptimizedStruct大小: %d字节
", unsafe.Sizeof(OptimizedStruct{})) // 16字节
// 获取字段偏移
var s AlignedStruct
fmt.Printf("字段a偏移: %d
", unsafe.Offsetof(s.a))
fmt.Printf("字段b偏移: %d
", unsafe.Offsetof(s.b))
fmt.Printf("字段c偏移: %d
", unsafe.Offsetof(s.c))
}
实战应用
构建器模式
type QueryBuilder struct {
table string
columns []string
where []string
orderBy string
limit int
}
func NewQueryBuilder(table string) *QueryBuilder {
return &QueryBuilder{
table: table,
columns: []string{},
where: []string{},
}
}
func (qb *QueryBuilder) Select(columns ...string) *QueryBuilder {
qb.columns = append(qb.columns, columns...)
return qb
}
func (qb *QueryBuilder) Where(condition string) *QueryBuilder {
qb.where = append(qb.where, condition)
return qb
}
func (qb *QueryBuilder) OrderBy(column string) *QueryBuilder {
qb.orderBy = column
return qb
}
func (qb *QueryBuilder) Limit(n int) *QueryBuilder {
qb.limit = n
return qb
}
func (qb *QueryBuilder) Build() string {
query := "SELECT "
if len(qb.columns) == 0 {
query += "*"
} else {
query += strings.Join(qb.columns, ", ")
}
query += " FROM " + qb.table
if len(qb.where) > 0 {
query += " WHERE " + strings.Join(qb.where, " AND ")
}
if qb.orderBy != "" {
query += " ORDER BY " + qb.orderBy
}
if qb.limit > 0 {
query += fmt.Sprintf(" LIMIT %d", qb.limit)
}
return query
}
// 使用示例
func main() {
query := NewQueryBuilder("users").
Select("id", "name", "email").
Where("age > 18").
Where("status = 'active'").
OrderBy("created_at DESC").
Limit(10).
Build()
fmt.Println(query)
// 输出: SELECT id, name, email FROM users WHERE age > 18 AND status = 'active' ORDER BY created_at DESC LIMIT 10
}
单例模式
type Database struct {
connection string
}
var (
instance *Database
once sync.Once
)
func GetDatabase() *Database {
once.Do(func() {
instance = &Database{
connection: "mysql://localhost:3306/mydb",
}
})
return instance
}
func (db *Database) Query(sql string) {
fmt.Printf("执行查询: %s
", sql)
}
写在最后
Go语言的结构体与方法设计体现了”组合优于继承”的思想。通过结构体,我们可以组织数据;通过方法,我们可以定义行为;通过嵌入,我们可以实现代码复用。
这种设计虽然简单,但功能强劲。它避免了传统面向对象语言中继承带来的复杂性,同时提供了足够的灵活性来构建复杂的系统。
作为Go开发者,理解结构体与方法的设计思想不仅有助于我们写出更好的代码,还能协助我们在设计系统时做出更好的架构决策。
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END




![在苹果iPhone手机上编写ios越狱插件deb[超简单] - 鹿快](https://img.lukuai.com/blogimg/20251123/23f740f048644a198a64e73eeaa43e60.jpg)













暂无评论内容