引言
l. 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)关联,耦合性低,也非常灵活。后面同学们会充分体会到这个特点。也就是说在 Golang中面向接口编程是非常重要的特性。
类型系统
类型系统是指一个语言的类型体系结构。一个典型的类型系统通常包含如下基本内容:
- 基础类型:int,bool,float等
- 复合类型,如数组、结构体、指针等
- 值语义和引用语义
- 面向对象,即所有具备面向对象特征(比如成员方法)的类型
- 接口
值语义和引用语义
结构体基本语法
type 结构体名称
struct {
field1
type
field2
type
}
type Cat
struct {
Name
string
Age
int
Color
string
Hobby
string
}
// 创建结构体变量的方式
var cat Cat
var cat Cat = Cat{
"中分",
3,
"黑白",
"吃鱼"}
// 必须字段顺序对应
var cat Cat = Cat{Name :
"中分", Age :
3, Color :
"黑白", Hobby :
"吃鱼"}
// 字段顺序可以不对应
var cat *Cat =
new(Cat)
// 返回的结构体指针
var cat *Cat = &Cat{}
// 返回结构体指针
// 结构体指针的调用方式
(*cat).Name =
"杜甫" <-----> cat.Name =
"杜甫" // 两个等价,因为go设计者为了程序员使用方便,底层会对cat.Name进行处理,加上*,这是一个语法糖
- 结构体是自定义的数据类型,代表一类事物
- 结构体变量是具体的,实际地,代表一个具体变量
- 结构体的所有字段在内存中的分布是连续的
type Point
struct {
x
int
y
int
}
type Rect1
struct {
// x, y四个int全部连续
leftUp, rightDown Point
}
type Rect2
struct {
// 指针变量内存连续
leftUp, rightDown *Point
}
- 不同结构体变量的字段是独立,互不影响,一个结构体变量字段的更改,不影响另外一个,结构体是值类型
- 结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段
- 结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
- struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
方法
方法:即结构体的行为
Golang 中的方法是作用在指定的数据类型上的,因此自定义类型,都可以有方法,而不仅仅是struct
// 声明
func (recevier type) methodName (参数列表) (返回值列表) {
方法体
return 返回值
// 不是必须的
}
type A
struct {
Num
int
}
func (a A) test0(){
// a 是副本
...
}
func (a *A) test1(){
// a 是结构体指针,结构体变量调用的时候,会传递地址给a
...
}
- 方法只能通过结构体变量来调用
- 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
- 如果希望能在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理
- Golang中的方法作用在指定的数据类型上的(即:和指定数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct
- 方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其他包访问
- 如果一个类型实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出
方法与函数的区别
调用方式不一样
- 函数的调用方式:函数名(实参列表)
- 方法的调用方式:变量.方法名(实参列表)
对应普通函数,接收者为值类型,不能将指针类型的数据直接传递
工厂模式(构造函数)
如果结构体的首字母是大写的,那么我们可以在其他包访问,并且创建它的变量,但是如果结构体首字母是小写,其他包访问不了,就需要用工厂模式来创建变量
<a href="https://github.com/users/duogaobingh5/projects/1">https://github.com/users/duogaobingh5/projects/1</a>
<a href="https://www.github.com/users/duogaobingh5/projects/1">https://www.github.com/users/duogaobingh5/projects/1</a>
<a href="http://github.com/users/duogaobingh5/projects/1">http://github.com/users/duogaobingh5/projects/1</a>
<a href="https://github.com/users/duogaobingh5/projects/1?fullscreen=true">https://github.com/users/duogaobingh5/projects/1?fullscreen=true</a>
<a href="https://github.com/users/chongmur946/projects/1">https://github.com/users/chongmur946/projects/1</a>
<a href="https://www.github.com/users/chongmur946/projects/1">https://www.github.com/users/chongmur946/projects/1</a>
<a href="http://github.com/users/chongmur946/projects/1">http://github.com/users/chongmur946/projects/1</a>
<a href="https://github.com/users/chongmur946/projects/1?fullscreen=true">https://github.com/users/chongmur946/projects/1?fullscreen=true</a>
<a href="https://github.com/users/gwwjrh78823/projects/1">https://github.com/users/gwwjrh78823/projects/1</a>
<a href="https://www.github.com/users/gwwjrh78823/projects/1">https://www.github.com/users/gwwjrh78823/projects/1</a>
<a href="http://github.com/users/gwwjrh78823/projects/1">http://github.com/users/gwwjrh78823/projects/1</a>
<a href="https://github.com/users/gwwjrh78823/projects/1?fullscreen=true">https://github.com/users/gwwjrh78823/projects/1?fullscreen=true</a>
<a href="https://github.com/users/duogaobingh5/projects/2">https://github.com/users/duogaobingh5/projects/2</a>