Golang第五章:结构体、对象、文件、序列化操作
Golang面向对象
1. Golang没有类,Go的结构体相对于其它编程语言的类
2. Golang去掉了传统OOP语言的继承、方法重载、构造函数和析构函数、隐藏的指针等等
3. Golang仍有面向对象编程的继承、封装和多态的特性,只是实现方式不同
创建结构体实例的四种方法
type Cat struct { Name string Age int Color string } func main() { // 结构体实例创建方式1 var cat1 Cat cat1.Name = "小白" // 方式2 cat2 := Cat{"haha", 13, "红"} fmt.Println(cat2) fmt.Println(cat1) // 方式3 var cat3 *Cat = new(Cat) (*cat3).Name = "小花" // 以上也可以写成cat3.Name = "小花" // 原因:go的设计者为了程序员使用方便,底层会对以上语句进行处理,会转化成(*cat3) // 方式4 // 下面的语句,也可以直接给字段赋值 // var cat4 *Cat = &Cat{"haha", 321, "绿"} var cat4 *Cat = &Cat{} (*cat4).Name = "小曹" // 以上也可以写成cat3.Name = "小花" // 原因:go的设计者为了程序员使用方便,底层会对以上语句进行处理,会转化成(*cat3) fmt.Println(*cat4) fmt.Println(*cat3) fmt.Println(cat2) fmt.Println(cat1) }
结构体的注意事项
1. 结构体的所有字段在内存中是连续的
2. 对一个结构体进行type重新定义,Golang认为是新的数据类型,但相互间可以强转
3. 结构体的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
4. 如果一个变量实现了String()方法,那么fmt.Println默认会调用这个变量的String()进行输出——该功能与java的toString()一致
5. 不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定——如func (cat *Cat)为地址拷贝,func (cat Cat)为值拷贝
结构体序列化
import ( "fmt" "encoding/json" ) type Cat struct { Name string `json: "name"` Age int `json:"age"` Color string `json:"skill"` } func main() { // 方式2 cat2 := Cat{"haha", 13, "红"} jsonStr, err := json.Marshal(cat2) if err != nil { fmt.Println("json 处理错误", err) } fmt.Println("jsonStr", string(jsonStr)) }
结构体绑定方法
创建结构体实例指定字段值
工厂模式
package main import ( "fmt" "go_code/project05/factory/model" ) func main() { var str = model.NewStudent("tom~", 89.2) fmt.Println(str) fmt.Println("score:", str.GetScore()) } package model //定义一个结构体 type student struct { Name string score float64 } func NewStudent(n string, s float64) *student { return &student { Name: n, score: s, } } func (s *student)GetScore() (float64) { return s.score }
继承
结构体可以使用嵌套结构体所有的方法和字段,无论首字母大小写
package main import ( "fmt" ) // 学生 type Student struct { Name string Age int Score int } func (stu *Student) showInfo() { fmt.Printf("学生名=%v 年龄=%v 成绩=%v\n", stu.Name, stu.Age, stu.Score) } func (stu *Student) SetScore(score int) { stu.Score = score } // 小学生 type Pupil struct { Student } func (p *Pupil) Testing() { fmt.Println("小学生在考试") } func main() { pupil := &Pupil{} pupil.Student.Name = "tom~" pupil.Student.Age = 8 pupil.Testing() pupil.SetScore(25) pupil.showInfo() }
接口
// 声明一个接口 type Usb interface { Start() Stop() } type Phone struct { } func (p Phone) Start() { fmt.Println("phone start") } func (p Phone) Stop() { fmt.Println("phone bomb") } type Computer struct { } func (c Computer) Working(usb Usb) { usb.Start() usb.Stop() } func main() { computer := Computer{} phone := Phone{} computer.Working(phone) // 输出phone start、phone bomb }
一个自定义类型(不止是结构体)只有实现了某个接口,才能将自定义类型的实例(变量)赋给接口类型
// 声明一个接口 type Usb interface { Start() } type Phone struct { } type integer int func (i integer) Start() { fmt.Println("integer Start") } func (p Phone) Start() { fmt.Println("phone start") } func main() { var phone Phone var usb Usb = phone usb.Start() var i integer var usb2 Usb = i usb2.Start() }
类型断言
类型断言(Type Assertion)是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型。
type Point struct { x int y int } func main() { var a interface{} var point Point = Point{1, 2} a = point var b Point b, ok := a.(Point) if ok { fmt.Println("convert success") } else { fmt.Println("convert failed") } fmt.Println(b) }
文件操作
读取文件——缓存读取
import ( "fmt" "os" "bufio" "io" ) func main() { file, err := os.Open("D:/project/goproject/src/go_code/fileWriter") if err != nil { fmt.Println("open file err=", err) } defer file.Close() // 当函数退出时,要及时关闭file // 用带缓冲的Reader读取文件 reader := bufio.NewReader(file) for { str, err := reader.ReadString('\n') if err == io.EOF { break } fmt.Print(str) } fmt.Println("文件读取结束...") }
读取文件——一次性读取(适用文件不大情况)
import ( "fmt" "io/ioutil" ) func main() { // 使用io.ioutil.ReadFile一次性将文件读取到位 file := "D:/project/goproject/src/go_code/fileWriter/111.txt" content, err := ioutil.ReadFile(file) if err != nil { fmt.Printf("read file err=%v", err) } fmt.Printf("%v", string(content)) }
写文件操作
通过缓存区写文件
import ( "fmt" "os" "bufio" ) func main() { // 使用io.ioutil.ReadFile一次性将文件读取到位 file := "D:/project/goproject/src/go_code/fileWriter/111.txt" f, err := os.OpenFile(file, os.O_WRONLY | os.O_CREATE, 0666) if err != nil { fmt.Printf("open file err=%v\n", err) } defer f.Close() //准备写入hello str := "hello" writer := bufio.NewWriter(f) //使用带缓存的writerString for i := 0; i < 5; i++ { writer.WriteString(str) } writer.Flush() }
序列化/反序列化操作
import ( "fmt" "encoding/json" ) type Monster struct { Name string `json:"monster_name"` //反射机制 Age int `json:"monster_age"` Birthday string Sal float64 Skill string } func testStruct() { monster := Monster { Name: "牛魔王", Age: 500, Birthday: "2021-11-11", Sal: 8000.0, Skill: "牛魔全", } data, err := json.Marshal(&monster) if err != nil { fmt.Printf("序列号错误 err=%v\n", err) } // 输出序列化后的结果 fmt.Printf("monster序列化后的结果=%v\n", string(data)) } // 将map进行序列化 func testMap() { // 定义一个map var a map[string]interface{} a = make(map[string]interface{}) a["name"] = "红孩儿" a["age"] = 34 a["address"] = "洪崖洞" data, err := json.Marshal(a) if err != nil { fmt.Printf("序列号错误 err=%v\n", err) } // 输出序列化后的结果 fmt.Printf("a map 序列化后的结果=%v\n", string(data)) } // 对切片进行序列化 func testSlice() { var slice []map[string]interface{} var m1 map[string]interface{} m1 = make(map[string]interface{}) m1["name"] = "jack" m1["age"] = 7 m1["address"] = "shanghai" slice = append(slice, m1) var m2 map[string]interface{} m2 = make(map[string]interface{}) m2["name"] = "tom" m2["age"] = 20 m2["address"] = "shanghai" slice = append(slice, m2) data, err := json.Marshal(slice) if err != nil { fmt.Printf("序列号错误 err=%v\n", err) } // 输出序列化后的结果 fmt.Printf("slice 序列化后的结果=%v\n", string(data)) } func main() { // 演示将结构体,map,切片进行序列化 testStruct() testMap() testSlice() }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App