当前位置: 首页 > news >正文

Go初级之五:结构体与方法

Go初级之五:结构体与方法

在Go语言中,结构体(struct)方法(method) 是实现面向对象编程的核心机制。虽然Go不是传统意义上的面向对象语言(没有类、继承等概念),但通过结构体和方法的组合,可以非常优雅地组织代码。


一、结构体(Struct)

1. 什么是结构体?

结构体是一种自定义的数据类型,用于将多个不同类型的数据字段组合在一起,形成一个有意义的整体。

类比:就像“学生”这个概念,包含姓名、年龄、成绩等多个属性。

2. 定义结构体

type Student struct {Name  stringAge   intScore float64
}
  • type:关键字,用于定义新类型。
  • Student:结构体名称(大写表示对外可见)。
  • {} 内是字段列表,每个字段有名字和类型。

3. 创建结构体实例

方式一:使用 struct{} 字面量
s1 := Student{Name: "张三",Age: 18,Score: 95.5,
}
方式二:按顺序赋值(不推荐,易错)
s2 := Student{"李四", 17, 88.0}
方式三:new 创建指针
s3 := new(Student)
s3.Name = "王五"
s3.Age = 19
s3.Score = 90.0
// 等价于 s3 := &Student{}

4. 访问结构体字段

fmt.Println(s1.Name)   // 输出:张三
fmt.Println(s1.Age)    // 输出:18
s1.Score = 96.0        // 修改字段

二、方法(Method)

1. 什么是方法?

方法是绑定到某个类型上的函数。在Go中,你可以为结构体(甚至基本类型)定义方法。

2. 定义方法

语法:

func (接收者 变量名 类型) 方法名(参数列表) 返回值 {// 方法体
}
示例:为 Student 定义一个方法
func (s Student) PrintInfo() {fmt.Printf("姓名: %s, 年龄: %d, 成绩: %.2f\n", s.Name, s.Age, s.Score)
}func (s Student) IsPass() bool {return s.Score >= 60
}
调用方法:
s := Student{"张三", 18, 95.5}
s.PrintInfo()  // 姓名: 张三, 年龄: 18, 成绩: 95.50
fmt.Println(s.IsPass()) // true

3. 值接收者 vs 指针接收者

❌ 值接收者(不会修改原结构体)
func (s Student) SetName(name string) {s.Name = name // 只修改副本
}

调用后原结构体不变。

✅ 指针接收者(可以修改原结构体)
func (s *Student) SetName(name string) {s.Name = name // 修改原始结构体
}

调用:

s := Student{"张三", 18, 95.5}
s.SetName("李四")
fmt.Println(s.Name) // 输出:李四

建议:如果方法需要修改结构体,或结构体较大(避免复制开销),使用指针接收者。


三、结构体的高级用法

1. 匿名字段(模拟“继承”)

Go没有继承,但可以通过匿名字段实现类似效果。

type Person struct {Name stringAge  int
}type Student struct {Person  // 匿名字段Score   float64School  string
}

使用:

s := Student{Person: Person{Name: "张三", Age: 18},Score:  95.5,School: "清华",
}fmt.Println(s.Name)  // 直接访问匿名字段的属性
fmt.Println(s.Age)
fmt.Println(s.Score)

这叫“组合”,不是继承,是Go推崇的设计模式。


2. 结构体标签(Struct Tag)——常用于JSON序列化

type User struct {ID   int    `json:"id"`Name string `json:"name"`Age  int    `json:"age"`
}

使用 json.Marshal

u := User{ID: 1, Name: "Alice", Age: 25}
data, _ := json.Marshal(u)
fmt.Println(string(data)) 
// 输出:{"id":1,"name":"Alice","age":25}

常见用途:JSON、数据库ORM(如GORM)、表单验证等。


四、完整示例:学生管理系统

package mainimport "fmt"// 1. 定义结构体
type Student struct {Name  stringAge   intScore float64
}// 2. 定义方法
func (s Student) Print() {fmt.Printf("学生: %s, 年龄: %d, 成绩: %.2f\n", s.Name, s.Age, s.Score)
}func (s *Student) Promote() {s.Age++fmt.Printf("%s 升了一岁,现在 %d 岁\n", s.Name, s.Age)
}func (s Student) IsExcellent() bool {return s.Score >= 90
}// 3. 主函数
func main() {s := Student{"张三", 18, 95.5}s.Print()           // 学生: 张三, 年龄: 18, 成绩: 95.50fmt.Println(s.IsExcellent()) // trues.Promote()         // 张三 升了一岁,现在 19 岁
}

五、最佳实践与注意事项

项目建议
结构体名驼峰命名,首字母大写表示导出
字段名同上,小写为包内私有
方法接收者小结构用值接收者,大结构或需修改时用指针
组合代替继承多用匿名字段组合,少用嵌套
使用TagJSON、数据库操作时务必使用

六、常见面试题

  1. 值接收者和指针接收者的区别?

    • 值接收者:操作副本,不改变原值。
    • 指针接收者:操作原值,可修改。
  2. Go有继承吗?

    • 没有,但可以通过匿名字段实现组合。
  3. 什么时候用指针接收者?

    • 方法会修改结构体。
    • 结构体较大(避免复制开销)。
    • 保持一致性(同一个类型的方法尽量统一用指针或值)。

✅ 总结

概念说明
struct自定义复合数据类型
method绑定到类型的函数
接收者(s Type)(s *Type)
匿名字段实现组合,“has-a”关系
Struct Tag元信息,用于JSON、ORM等

下一节预告:Go初级之六:接口(Interface)—— 实现多态与解耦

http://www.xdnf.cn/news/1394425.html

相关文章:

  • 【leetcode】114. 二叉树展开为链表
  • 【Rust】 6. 字符串学习笔记
  • app怎么防止被攻击被打有多少种防护方式?
  • 税务岗位能力提升培训课程推荐
  • 达梦数据库-数据缓冲区 (二)
  • 【Flask】测试平台开发,产品管理实现编辑功能-第六篇
  • 接吻数问题:从球体堆叠到高维空间的数学奥秘
  • 机器学习 - Kaggle项目实践(5)Quora Question Pairs 文本相似
  • 栈和队列OJ习题
  • 佳易王钓场计时计费系统:全方位赋能钓场智能化管理,软件操作教程
  • vue在函数内部调用onMounted
  • 2025年热门职业资格证书分析
  • Rust 登堂 之 深入Rust 类型(六)
  • Linux内存管理 - LRU机制
  • 「LangChain 学习笔记」LangChain大模型应用开发:代理 (Agent)
  • VeOmni 全模态训练框架技术详解
  • 蓝蜂蓝牙模组:破解仪器仪表开发困境
  • 《P2863 [USACO06JAN] The Cow Prom S》
  • C++模板类的详细介绍和使用指南
  • 桌面GIS软件添加第三方图层
  • 【无标题】透明显示屏设计,提升展厅视觉体验边界
  • 【0424】为用户指定(CREATE TABLE)的 table 创建 relcache entry,并将其注册到 relcache ④
  • ros2--action/动作--接口
  • 【链表 - LeetCode】146. LRU 缓存
  • LeetCode Hot 100 Python (11~20)
  • Windows 11 跳过 OOBE 的方法和步骤
  • 打工人日报#20250829
  • 亚马逊季节性产品运营策略:从传统到智能化的演进
  • 【AOSP】Android Dump 开发与调试指南
  • 麒麟系统使用-VSCode运行.net过程中一些可能问题及解决办法