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本身就是语言类型系统(typesystem)的一部分,通过接口(interface)关联,耦合性低,也非常灵活。后面会充分体会到这个特点。也就是说在Goalng中面向接口编程是非常重要的特性。
看一个养猫猫问题:
张老太养了两只猫猫:一只名字叫小白,今年3岁,白色。还有一只叫小花,今年100岁,花色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示张老太没有这只猫猫。
使用现有技术解决:
1)单独的定义变量解决
funcmain(){
//1.使用变量的处理varcat1Namestring="小白"varcat1Ageint=3varcat1Colorstring="白色"
varcat2Namestring="小花"varcat1Ageint=100varcat1Colorstring="花色"}
2)使用数组解决
//2.使用数组解决varcatNames[2]string=[..]string{"小白","小花"}varcatAges[2]int=[..]int{3,100}varcatColers[2]string=[..]string{"白色","花色"}}
现有技术结局的缺点分析:
1)使用变量或者数组来解决养猫的问题,都不利于数据的管理和维护。因为名字,年龄,颜色都是属于一只猫,但是这里是分开保存。
2)如果我们希望对一只猫的属性(名字、年龄、颜色)进行操作(绑定方法)也不好处理。
3)引出我么要讲解的技术==》结构体
结构体与结构体变量(实例/对象)的关系示意图:
对上图说明:
1)将一类事物的特征提取出来(比如猫类),形成一个新的数据类型,就是一个结构体。
2)通过这个结构体,我们可以创建多个变量(实例/对象)
3)事物可以是猫类,也可以是Person,Fish或是某个工具类。。。
快速入门-面向对象的方式(struct)解决养猫问题
packagemainimport("fmt")
//定义一个Cat结构体,将Cat的各个字段/属性信息,放入到Cat结构体进行管理typeCatstruct{NamestringAgeintColorstringHobbystring}
//张老太养了两只猫猫:一只名字叫小白,今年3岁,白色。//还有一只叫小花,今年100岁,花色。//请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,//年龄,颜色。如果用户输入的小猫名错误,//则显示张老太没有这只猫猫。
//使用struct来完成案例//创建一个Cat的变量
varcat1Cat//varaintcat1.Name="小白"cat1.Age=3cat1.Color="白色"cat1.Hobby="吃鱼"fmt.Println("cat1=",cat1)
fmt.Println("猫猫的信息如下:")fmt.Println("name=",cat1.Name)fmt.Println("age=",cat1.Age)fmt.Println("color=",cat1.Color)fmt.Println("hobby=",cat1.Hobby)}
结构体和结构体变量(实例)的区别和联系:
通过前面的案例和讲解我们可以看出:
1)结构体是自定义的数据类型,代表一类事物
2)结构体变量(实例)是具体的,实际的,代表一个具体变量
结构体变量(实例)在内存中的布局:
type结构体名称struct{field1typefield2type}
举例:
typeStudentstruct{NamestringAgeintScorefloat32}
‘字段/属性
基本介绍:
1)从概念或叫法上看:结构体字段=属性=field(即授课中,统一叫字段)
2)字段是结构体的一个组成部分,一般是基本数据类型、数组,也可以是引用类型。比如我们前面定义猫结构体的Namestring就是属性
注意事项和细节说明:
2)字段的类型可以为:基本类型、数组或引用类型
3)在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值(默认值),规则同前面讲的一样:
案例演示:
//如果结构体的字段类型是:指针,slice,和map的零值都是nil,即还没有分配空间//如果需要使用这样的字段,需要先make,才能使用。
typePersonstruct{NamestringAgeintScores[5]float64ptr*int//指针slice[]int//切片map1map[string]string//切片}
//定义一个结构体变量varp1Personfmt.Println(p1)ifp1.ptr==nil{fmt.Println("ok1")}ifp1.slice==nil{fmt.Println("ok2")}ifp1.map1==nil{fmt.Println("ok3")}
//使用slice,再次说明,一定要makep1.slice=make([]int,10)p1.slice[0]=100
//使用map,也一定要先makep1.map1=make(map[string]string)p1.map1["key1"]="tom"fmt.Println(p1)}
4)不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,不影响另外一个。
typeMonsterstruct{NamestringAgeint}
varmonster1Monstermonster1.Name="牛魔王"monster1.Age=500
monster2:=monster1//结构体是值类型,默认为值拷贝monster2.Name="青牛精"
fmt.Println("monster1=",monster1)fmt.Println("monster2=",monster2)}