GO学习笔记 之面向对象编程[结构体]
1.结构体的开篇
一个没有结构体的例子:
package main
import "fmt"
func main() {
// 1.变量
var cat01Name string = "cat_hei"
var cat01Age int = 3
fmt.Println(cat01Name,cat01Age)
var cat02Name string = "cat_bai"
var cat02Age int = 4
fmt.Println(cat02Name,cat02Age)
// 2.数组
var catNames [2]string = [...]string{"hei","bai"}
var catAges [2]int = [...]int{3,4}
fmt.Println(catNames,catAges)
//
}
使用结构体:结构体对于其他语言就是对象
2.GO语言面向对象编程说明
(1)golang也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所有我们说Golang支持面向对象编程特性是比较准确的。
(2)Golang没有类(class),GO语言的结构体(struct)和其他语言的类(class)有同等的地位,你可以理解Golang是基于struct来实现OOP特性的。
(3)Golang面向对象编程非常简洁,去掉了传统OOP语言的继承,方法重载,构造函数和析构函数,隐藏的this指针等待
(4)Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其他OOP语言不一样,比如继承:Golang没有extends关键字,继承是通过匿名字段来实现。
(5)Golang面向对象(OOP)很优雅,OOP本身就是语言类型系统(type system)的一部分,通过接口(interface)关联,耦合性低,也非常灵活。面向接口编程的思想。
结构体(类)----实例(变量)
package main
import "fmt"
// // 定义一个结构体
type Cat struct{
Name string
Age int
Color string
}
func main() {
//使用结构体
var cat1 Cat // 使用一个结构体
cat1.Name = "bai"
cat1.Age = 2
cat1.Color = "white"
// fmt.Println(cat1)
fmt.Println("Name = ",cat1.Name)
fmt.Println("Age = ",cat1.Age)
fmt.Println("Color = ",cat1.Color)
}
1.结构体是自定义的数据类型,代表一类事物。
2.结构体变量(实例)是具体的,实际的,代表一个具体变量。
结构体是一种值类型数据。
声明结构体语法:
type 结构体名称 struct {
filed1 type
field2 type
field3 type
}
3.结构体的字段/属性
(1)基本介绍:
1.从概念上加法:结构体字段=属性=field
2.字段是结构体的一个组成部分,一般是基本数据类型,数组,也是引用类型。
(2)注意事项和细节说明
1.字典声明语法变量,示例: 字段名 字段类型
2.字段的类型可以为:基本类型、数组或引用类型
3.在创建一个结构体变量,如果没有给字段赋值都有对应的默认值。大概如下:
布尔类型是false,数值是0,字符串是””
数组类型默认值和它的元素类型相关,比如 score[3] int则为[0,0,0]
指针,slice和map的默认值是nil,即没有分配空间。
4.结构体的字段是独立的,互不影响,一个结构体变量字段的更改,不影响另外一个。
结构体里使用:数组,slice和map的数据
package main
import "fmt"
// 如果结构体的字段为:指针,slice和map的默认值都是nil
// 如果需要使用这些字段,需要先make才能使用
type Person struct {
Name string
Age int
Scores [5]float64 //
ptr *int // 指针
Slice []int // 切片
Map map[string]string // map
}
func main(){
// 定义结构体
var person1 Person
fmt.Println(person1) // { 0 [0 0 0 0 0] <nil> [] map[]}
if person1.ptr == nil{
fmt.Println("ok1")
}
if person1.Slice == nil {
fmt.Println("ok2")
}
if person1.Map == nil {
fmt.Println("OK3")
}
// 使用slice先make
person1.Slice = make([]int,10)
person1.Slice[0] = 10
fmt.Println(person1.Slice)
// 使用map先make
person1.Map = make(map[string] string)
person1.Map["hh"] = "666"
fmt.Println(person1.Map)
}
结构体里面的属性之间不会相互影响例子:
package main
import "fmt"
type Cat struct{
Name string
Age int
}
func main(){
//
var cat1 Cat
cat1.Name = "bai"
cat1.Age = 2
cat2 := cat1
cat2.Age = 3
fmt.Println(cat1)
fmt.Println(cat2)
}
4.创建结构体变量和访问结构体方式
方式1:直接声明
var person01 Person
方式2:{}
p2 := Person{"two",20}
方式3:&
var p3 *Person = new(Person)
方式4:
例子如下:
package main
import "fmt"
type Person struct{
Name string
Age int
}
func main(){
// 方式1:var p1 Person
var p1 Person
p1.Name = "one"
p1.Age = 19
fmt.Println(p1)
// 方式2:p2 := Person{"two",20}
p2 := Person{"two",20}
fmt.Println(p2)
// 方式3:
var p3 *Person = new(Person) // p3为结构体的指针
// 因为p3是个指针,因此标准的写法如下:
(*p3).Name = "Three"
(*p3).Age = 21
fmt.Println(p3)
// 可简化为:因为创建者底层对上面指针做了处理
// p3.Name = "Three"
// p3.Age = 21
// 方式4:var p4 *Person = &Person()\
// p4为指针
var p4 *Person = &Person{} // 也可以直接在{}进行赋值
(*p4).Name = "four"
(*p4).Age = 22
fmt.Println(p4) // p4为结构体的指针
fmt.Println(p4.Name)
fmt.Println(p4.Age)
}
5.结构体的内存分配机制
例:
package main
import "fmt"
type Person struct{
Name string
Age int
}
func main(){
// 以下p1 和 p2 共享一个内存地址
var p1 Person
p1.Age = 10
p1.Name = "小明"
var p2 *Person = &p1 // p2是一个指针
fmt.Println((*p2).Age) //golang中 (*p2) 与 p2相同
fmt.Println(p2.Age)
p2.Name = "SIX"
fmt.Println(p2.Name)
fmt.Println(p1.Name)
fmt.Println((*p2).Name)
}
6.结构体的注意事项和使用细节
(1)结构体的所有字段的内存是连续的[例1]
(2)两个结构体间转换必须两个结构体字段相同[例2]
(3)结构体进行type重新定义(相当于取别名),Golang认为是重新定义数据类型,但是互相之间可以强转。[例2]
(4)struct的每个字段,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化。
例子1:
package main
import "fmt"
type Point struct {
x int
y int
}
type Rect struct {
leftUp, rightDown Point
}
type RectPointer struct {
leftUp, rightDown *Point
}
func main() {
//
r1 := Rect{Point{1, 2}, Point{3, 4}}
// r1 有4个int ,在内存中是连续分布的
fmt.Println("r1.leftUp.x地址:", &r1.leftUp.x)
fmt.Println("r1.leftUp.y地址:", &r1.leftUp.y)
fmt.Println("r1.rightDown.x地址:", &r1.rightDown.x)
fmt.Println("r1.rightDown.x地址:", &r1.rightDown.y)
// // 八进制 一个地址八个字节
/*
r1.leftUp.x地址: 0xc000054120
r1.leftUp.y地址: 0xc000054128
r1.rightDown.x地址: 0xc000054130
r1.rightDown.x地址: 0xc000054138
*/
fmt.Println("结构体下面的值为地址的情况")
r2 := RectPointer{&Point{1, 2},&Point{3, 4}}
fmt.Println("r2.leftUp.x地址:", &r2.leftUp.x)
fmt.Println("r2.leftUp.y地址:", &r2.leftUp.y)
fmt.Println("r2.rightDown.x地址:", &r2.rightDown.x)
fmt.Println("r2.rightDown.x地址:", &r2.rightDown.y)
fmt.Println(r2.rightDown.x) // x值
}
例2:
package main
import "fmt"
type A struct{
Num int
}
type B struct{
Num int
}
func main() {
// 如果要在两个结构体间转换必须两个结构体字段相同
// 字段个数,字段名称,字段类型相同
var a A
var b B
a = A(b) // 强转
fmt.Println(a,b)
例4:
package main
import "fmt"
import "encoding/json"
type Monster struct{
Name string `json:"name"` // `json:"name"` 这个就是结构体的标签
Age int `json:"age"` // 效果是可以首字母大写的变量可以在json返回小写
Skill string `json:"skill"`
}
func main(){
// 1.创建一个Monster变量
monster := Monster{"ZEOR",25,"coding go"}
// 2.将monster变量序列化为json格式的字符串
jsononster,err := json.Marshal(monster)
if err != nil{
fmt.Println("json处理错误")
}
fmt.Println("jsononster:",string(jsononster)) // jsononster数据类型为bytes需求强转为string
}

浙公网安备 33010602011771号