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()
}