golang支持面向对象的设计,一般支持面向对象的语言都会有class的设计,但是golang没有class关键字,只有struct结构体。通过结构体达到类的效果,这叫做大成若缺,其用不弊。

struct简介

在使用struct之前,先介绍golang的一个特性,golang允许用户将类型A定义为另一种类型B,并为类型B添加方法。

1
2
3
4
type Integer int 
func (a Integer) Less (b Integer) bool{
return a < b
}

我们将int定义为一种新的类型Integer,Integer就和int不是一个类型了,这和C++不一样。然后为Integer添加了方法Less,所有Integer对象都可以使用Less方法。类似于C++的成员函数。下面我们使用一下

1
2
3
4
5
func main() {
var varint1 Integer = 100
var varint2 Integer = 200
fmt.Println(varint1.Less(varint2))
}

定义了两个变量varint1和varint2,调用了varint1的Less方法,输出true
下面介绍struct的基本定义

1
2
3
4
5
//构造函数和初始化
type Rect struct{
x,y float64
width, height float64
}

定义了一个结构体Rect,Rect包含四个成员,x,y为float64类型,width, height为float64类型。
下面为Rect定义方法,计算矩形面积

1
2
3
func (r* Rect) Area() float64{
return r.width* r.height
}

golang结构体没有public,private等字段,是通过成员的大小写区分权限的。大写的结构体成员,别的包可以访问,小写的成员不可被别的包访问。
Rect的成员都为小写,所以别的包无法访问,但是可以通过定义大写的方法,提供给别的包访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func (r *Rect) GetX() float64 {
return r.x
} func (r *Rect) GetY() float64 {
return r.y
} func (r *Rect) Area() float64 {
return r.width * r.height
} func (r *Rect) GetWidth() float64 {
return r.width
} func (r *Rect) GetHeight() float64 {
return r.height
}

这样其他的包就可以通过Rect的方法访问Rect内部变量值了。

结构体方法和函数的区别

结构体方法就好比是C++的成员函数,是类对象调用的方法。函数和结构体对象无关,可以自由编写。
二者定义也有区别

1
2
3
4
5
6
7
func (this* 结构体类型) 方法名(方法参数列表) 方法返回值{
//方法内部实现
} func 函数名(函数参数列表) 函数返回值{
//函数内部实现
}

golang的精髓是组合

1
2
3
4
5
6
7
8
9
type Inner struct {
Name string
Num int
} type Wrappers struct {
inner Inner
Name string
}

Wrappers 包含了Inner结构体,golang中叫做组合。下面写代码打印信息,我们先为Wrappers添加方法

1
2
3
4
5
func (wp *Wrappers) PrintInfo() {
fmt.Println(wp.Name)
fmt.Println(wp.inner.Name)
fmt.Println(wp.inner.Num)
}

定义变量调用方法

1
2
3
4
func main() {
wp := &Wrappers{Name: "wrapper", inner: Inner{Name: "inner", Num: 100}}
wp.PrintInfo()
}

打印结果如下

1
2
3
wrapper
inner
100

组合后,打印内部成员inner的Name需要显示指定wp.inner.Name,因为默认打印wp.Name是Wrappers的。

匿名组合实现继承(派生)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//匿名组合和派生
type Base struct {
Name string
} func (base *Base) Foo() {
fmt.Println("this is Base Foo")
} func (base *Base) Bar() {
fmt.Println("this is Base Bar")
} type Foo struct {
//匿名组合
Base
} func (foo *Foo) Foo() {
foo.Base.Foo()
fmt.Println("this is Foo Foo")
}

Foo内部组合了Base,但是并没有显示指定成员名,Foo内部只写了Base类型,这叫做匿名组合,
匿名组合会在Foo内部自动生成Base同名的成员变量Base,golang根据匿名组合,会认为Foo继承自Base,
从而Foo拥有Base的方法和成员。下面写代码看看效果

1
2
3
4
5
6
7
8
9
10
11
func main() {
foo := &Foo{}
//Foo继承Base,所以拥有Name属性
foo.Name = "foobase"
//Foo 重写(覆盖)了Base的Foo
foo.Foo()
//Foo继承了Base的Bar函数
foo.Bar()
//显示调用基类Base的Foo
foo.Base.Foo()
}

由于Foo继承Base后重写了Foo方法,所以想要调用Base的Foo方法,需要显示调用。

匿名指针组合

匿名组合如果是指针类型,在子类对象定义时需要显示初始化基类指针,否则会出问题。
先定义匿名组合结构体

1
2
3
4
5
6
7
8
9
10
//匿名指针组合
type DerivePoint struct {
*Base
} func (derivep *DerivePoint) Foo() bool {
fmt.Println("this is DerivePoint Foo")
fmt.Println("inherit base ,name is ", derivep.Name)
return true
}

定义了DerivePoint类,和方法Foo,在Foo内部打印了derivep的Name,该Name继承自*Base
下面调用

1
2
dr := &DerivePoint{Base: &Base{Name: "base"}}
dr.Foo()

输出如下

1
2
this is DerivePoint Foo
inherit base ,name is base

可见输出了Name值。

匿名组合造成命名冲突

1
2
3
4
5
6
//重复定义,因为匿名组合默认用类型做变量名
type MyJob struct {
*Logger
Name string
*log.Logger // duplicate field Logger
}

MyJob匿名组合了Logger类和log.Logger类,由于匿名组合默认用类型做变量名,所以编译器会认为定义了两个Logger名的成员,
从而报错,所以匿名组合一定要注意这一点。

多重继承

golang 支持多重继承,实现多重继承只需要多个匿名组合即可。

golang(07)结构体介绍的更多相关文章

  1. Golang 入门 : 结构体(struct)

    Go 通过类型别名(alias types)和结构体的形式支持用户自定义类型,或者叫定制类型.试图表示一个现实世界中的实体. 结构体由一系列命名的元素组成,这些元素又被称为字段,每个字段都有一个名称和 ...

  2. 将c语言的结构体定义变成对应的golang语言的结构体定义,并将golang语言结构体变量的指针传递给c语言,cast C struct to Go struct

    https://groups.google.com/forum/#!topic/golang-nuts/JkvR4dQy9t4 https://golang.org/misc/cgo/gmp/gmp. ...

  3. [Windows内核分析]KPCR结构体介绍 (CPU控制区 Processor Control Region)

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 逆向分析操作系统内核代码至少需要具备两项技能: 段页汇编代码非常懂 ...

  4. Golang操作结构体、Map转化为JSON

    结构体生成Json package main import ( "encoding/json" "fmt" ) type IT struct { Company ...

  5. golang初始化结构体数组

    最近组里新项目要求用go来写,没办法只能边看文档边写代码,今天遇到郁闷的问题,查了好久最终发现居然是一个标点符号的导致的,遂纪录之 刚刚给一个接口写单元测试时想初始化一个结构体数组,然后遍历该数组并建 ...

  6. golang之结构体使用注意事项和细节

    1. 结构体的所有字段在内在中是连续的 2. 结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字.个数和类型) 3. 结构体进行type重新定义(相当于取别名),Golang认 ...

  7. Golang通过结构体解析和封装XML

    Golang解析和封装XML 解析XML成结构体Demo package main import ( "encoding/xml" "fmt" ) //我们通过 ...

  8. golang 对结构体进行格式化输出

    可以使用 `return fmt.Sprintf("%+v", *conf) ` 来打印结构体,包括结构体的key值.但是由于结构体内容较多,都在一行,所以希望可以格式化输出结构体 ...

  9. golang匿名结构体

    go语言定义结构体类型时可以仅指定字段类型而不指定字段名字.这种字段叫做匿名字段(anonymous field). Go语言有一个特性允许只声明一个成员对应的数据类型而不指名成员的名字:这类成员就 ...

随机推荐

  1. js栈和堆的区别

    一.  堆(heap)和栈(stack) 栈(stack)会自动分配内存空间,会自动释放.堆(heap)动态分配的内存,大小不定也不会自动释放. 二.  基本类型和引用类型 基本类型:简单的数据段,存 ...

  2. mysqldump 使用--tab=path参数时提示mysqldump: Got error: 1290: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement when executing 'SELECT INTO OUTFILE'

    报错: [root@zedu test]# mysqldump -h127.0.0.1 -uroot -p --single-transaction --add-drop-database --tab ...

  3. 浅谈响应式Web设计与实现思路

    是否还在为你的应用程序适配PC端,移动端,平板而苦苦思索呢,是否在寻找如何一套代码适配多终端方式呢,是否希望快速上手实现你的跨终端应用程序呢,是的话,那就看过来吧,本文阐述响应式UI设计相关理论基础, ...

  4. 快速数论变换NTT模板

    51nod 1348 乘积之和 #include <cmath> #include <iostream> #include <cstdio> #include &l ...

  5. js自定义事件CustomEvent、Event、TargetEvent

    1.Event Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态. 事件通常与函数结合使用,函数不会在事件发生前被执行! Event的事件都是系统自 ...

  6. Python—数据类型之字典(Dict)

    其它数据类型转成字典 arr1 = ['jack', 'rose', 'marry'] arr2 = [68, 85, 66] dict1 = dict(zip(arr1, arr2)) print( ...

  7. 课时5:POW,POS,DPOS(矿工/矿机,工作证明)

    比特币钱包

  8. 在Ubuntu 18.04系统中蓝牙鼠标连接失败问题的解决

    2018-08-22 16:00:35作者:谖瓞稿源:linux站 如果你在Ubuntu 18.04操作系统中有蓝牙鼠标连接失败问题,那就参考下面的解决方法处理. 解决方法 首先在系统终端下输入: b ...

  9. Android学习_广播接收器

    一.广播 1. 标准广播和有序广播 标准广播:异步,发出消息,所有接收器同时接收.但无法被截断 有序广播:同步,同一时刻只有一个广播接收器接收.可截断消息. 2. 广播注册 代码中注册(动态注册).A ...

  10. Python使用otp实现二步验证

    https://www.cnblogs.com/lori/p/11077161.html https://blog.coding.net/blog/two-factor-authentication ...