Golang04-面向对象struct

470 阅读5分钟

struct

Go不是一个纯面向对象的编程语言。Go语言采用更灵活的"结构体"替代了"类"

Go并没有提供类(class),但是它提供了结构体(struct),方法(method)可以在结构体上添加。与类相类似,结构体提供了捆绑数据和方法的行为。

Go语言面向对象主要学习结构体(struct)、方法(method)、接口(interface)

1.1结构体的定义

type 类型名 struct{
    成员属性1 类型1
    成员属性2 类型2
    成员属性3 类型3
}

Sample结构体实例化

package  main

import "fmt"

type Teacher struct {
	name string
	age int
	sex byte
}
func main()  {
	//1、var声明方式实例化结构体,初始化方式为:对象.属性=值
	var t1 Teacher
	fmt.Println(t1)
	fmt.Printf("%T\n,%v\n,%q  \n",t1,t1,t1)
	t1.name="JackMa"
	t1.age=10086
	t1.sex=1
	fmt.Println(t1)
	fmt.Println("---------------")
	//变量简短声明格式实例化结构体,初始化方式为:对象.属性=值
	t2:=Teacher{}
	t2.name="pink"
	t2.age=132
	t2.sex=1
	fmt.Println(t2)
	fmt.Println("-------------------------")
}
/*
{ 0 0}
main.Teacher
,{ 0 0}
,{"" '\x00' '\x00'}  
{JackMa 10086 1}
---------------
{pink 132 1}
-------------------------
*/

1.2结构体语法糖

package main

import "fmt"

type teacher struct {
	name string
	age int8
	sex byte
}

func SynSugar()  {
	//数组中的语法糖
	arr:=[6]int{10,20,30,40,50,60}
	arr2:=&arr
	fmt.Println((*arr2)[len(arr)-1])	//返回60
	fmt.Println(arr2[0])				//返回10
	//切片的语法糖
	arr3:=[4]int {100,200,300,400}
	arr4:=&arr3
	fmt.Println((*arr4)[len(arr3)-1])	//返回400
}

func main()  {
	//使用new()内置函数实例化struct
	emp1:=new(teacher)
	fmt.Printf("emp1:%T,\n%v\n,%p\n",emp1,emp1,emp1) //*main.teacher,&{ 0 0},0xc000004078
	(*emp1).age=100
	(*emp1).name="JackMa"
	(*emp1).sex=1
	fmt.Println("--------------")
	fmt.Println(emp1)						//&{JackMa 100 1}
	fmt.Println(*emp1)						//{JackMa 100 1}
	fmt.Println("--------------")
	SynSugar()
}

1.3结构体是值类型

深拷贝是拷贝值,浅拷贝是拷贝了指针。

package main

import "fmt"

type Dog struct {
	name string
	color string
	age int
	kind string
}

func main()  {
	//1、实现结构体的深拷贝
	//struct 是值类型,默认的复制就是深拷贝

	dog1:=Dog{"旺财","black",2,"我是旺财!"}
	fmt.Printf("d1:%T,%v,%p\n",dog1,dog1,&dog1) //返回d1:main.Dog,{旺财 black 2 我是旺财!},0xc000042040
	dog2:=dog1
	fmt.Printf("dog2:%T,%v,%p\n",dog2,dog2,&dog2)
	dog2.name="JackMa"
	fmt.Println(dog2)		//{JackMa black 2 我是旺财!}
	fmt.Println("-------------------------")
	//dog2.boyfriend="steven"  这里结构体里面没有定义的报错
	//2、实现结构体浅拷贝,通过new()函数实现
	dog4:=new(Dog)
	dog4.name="Tony Ma"
	dog4.color="white"
	dog4.age=100
	dog4.kind="cute"
	fmt.Printf("dog4: %T,%v,%p\n",dog4,dog4,&dog4) //返回dog4: *main.Dog,&{Tony Ma white 100 cute},0xc000006030
}

1.4结构体作为参数返回值

结构体作为参数返回值有两种方式,值传递和参数传递。(这里我有个小困惑,go里面有引用参数传递吗?))

package main

import "fmt"

type Flower struct {
	name,color string
}

func changeInfo(f Flower)  {
	f.name="月季"
	f.color="pink"
}

func changeInfo2(f *Flower)  {
	f.name="喇叭花"
	f.color="white"
}

//返回结构体
func getFlower1() Flower {
	f:=Flower{"多肉","pink"}
	return f
}

//返回结构体指针
func getFlower2()  *Flower{
	temp:=Flower{"芙蓉","ret"}
	fmt.Printf("%T,%v,%p\n",temp,temp,&temp) //main.Flower,{芙蓉 ret},0xc000020500
	f:=&temp
	return f
}

func main()  {
	//结构体作为参数的用法
	f1:=Flower{"玫瑰","red"}
	fmt.Printf("%T,%v,%p\n",f1,f1,&f1)
	changeInfo(f1)
	fmt.Printf("%T,%v,%p\n",f1,f1,&f1)   //main.Flower,{玫瑰 red},0xc0000203e0
	fmt.Println("------------------")
	changeInfo2(&f1)                          //加引用可变
	fmt.Printf("%T,%v,%p\n",f1,f1,&f1)   //main.Flower,{喇叭花 white},0xc0000203e0
	//结构体作为对象返回值的用法
	f2:=getFlower1()
	f3:=getFlower2()
	fmt.Println("-------------------")
	fmt.Printf("%T,%v,%p\n",f2,f2,&f2)	//main.Flower,{多肉 pink},0xc0000204e0
	fmt.Printf("%T,%v,%p\n",f3,f3,&f3)	//返回*main.Flower,&{芙蓉 ret},0xc000006030
}

getFlower2()函数里面的temp的地址和ret的结构体指针地址不一样。所以还是有引用传递的

1.5匿名结构体

匿名结构体就是不需要type来定义的结构体,创建匿名结构体时,同时要创建对象。匿名结构体由结构体定义和键值对初始化两部分组成。

package main

import (
	"fmt"
	"math"
)

func main()  {
	//匿名函数
	res:= func(a,b float64) float64{
		return math.Pow(a,b)
	}(2,3)                            
	fmt.Println(res)                 //返回8
	
	//匿名结构体
	addr:= struct {
		province,city string
	}{"西藏","拉萨"}
	fmt.Println(addr)                //返回{西藏 拉萨}
	cat:= struct {
		name,color string
		age int8
	}{"黑猫","白色",10}
	fmt.Println(cat)                 //{黑猫 白色 10}
}

1.6结构体的匿名字段

package main

import "fmt"
type User struct {
	string
	byte
	int8
	float64
}

func main()  {
	//实例化结构体
	user1:=User{"steven",'m',35,177.5}
	fmt.Println(user1) 		//返回{steven 109 35 177.5}

	//如果想一次输出姓名、年龄、身高、性别
	fmt.Printf("姓名:%s\n",user1.string)		//返回姓名:steven
	fmt.Printf("身高:%.2f\n",user1.float64)	//身高:177.50
	fmt.Printf("性别:%c\n",user1.byte)		//性别:m
	fmt.Printf("年龄:%d\n",user1.int8)		//年龄:35
}


1.7 结构体嵌套

结构体嵌套就是将一个结构体作为另一个结构体的属性(字段),这种结构就是结构体嵌套。结构体嵌套可以模拟为面向对象编程的以下两种关系

  1. 聚合关系:一个类作为另一个类的属性。
  2. 继承关系:一个类作为另一个类的子类。子类和符类的关系。

sample聚合关系

package main

import "fmt"

type Address struct {
	province,city string
}

type person struct {
	name string
	age int
	address *Address
}
func main()  {
	//模拟结构体对象之间的聚合关系
	p:=person{}
	p.name="Steven"
	p.age=19
	//赋值方法
	addr:=Address{}
	addr.province="西藏"
	addr.city="拉萨"
	p.address=&addr
	fmt.Println("姓名:",p.name,"age:",p.age,"province:",p.address.province,"city:",p.address.city)
	fmt.Println("----------------------------")
	p.address.city="林芝"
	fmt.Println("姓名:",p.name,"age:",p.age,"province:",p.address.province,"city:",p.address.city)
	//修改赋值对象addr是否影响Person对象的数据
	addr.city="日喀则"
	fmt.Println("姓名:",p.name,"age:",p.age,"province:",p.address.province,"city:",p.address.city)
	fmt.Printf("------------------\n")
	//赋值方法2
	p.address=&Address{"青海","西宁"}
	fmt.Println("姓名:",p.name,"age:",p.age,"province:",p.address.province,"city:",p.address.city)
}
/*
返回结果:
姓名: Steven age: 19 province: 西藏 city: 拉萨
----------------------------
姓名: Steven age: 19 province: 西藏 city: 林芝
姓名: Steven age: 19 province: 西藏 city: 日喀则
------------------
姓名: Steven age: 19 province: 青海 city: 西宁
*/

1.8模仿继承关系

studentS继承PersonS

package main

import "fmt"

type PersonS struct {
	name string
	age int
	sex string
}

type studentS struct {
	PersonS
	studentNum int64
}

func main()  {
	//结构嵌套体模拟继承关系
	p1:=PersonS{"JackMa",35,"男"}
	fmt.Println(p1)
	fmt.Println("--------------------------")
	//实例化并初始化Student
	//写法1
	s1:=studentS{p1,1008611}
	fmt.Println(s1)
	//写法2
	s2:=studentS{PersonS{"TonyMa",30,"男"},123456}
	fmt.Println(s2)
	//写法3
	s3:=studentS{}
	s3.studentNum=10323
	s3.age=102311
	s3.sex="男"
}