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. Spring——概念

    一.简介 Spring是一个开源的框架,Spring为简化企业级应用开发而生,使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能.Spring是一个IOC和AOP容器框架. ...

  2. 【技巧 二进制分组】bzoj4398: 福慧双修&&2407: 探险

    二进制分组也可以说是一种比较优美的拆贡献方式吧? Description 菩萨为行,福慧双修,智人得果,不忘其本.——唐朠立<大慈恩寺三藏法师传>有才而知进退,福慧双修,这才难得.——乌雅 ...

  3. 开启防火墙如何部署k8s

    你可以不关闭防火墙,只需要开启这些端口就行了MASTER节点6443* Kubernetes API server 2379-2380 etcd server client API 10250 Kub ...

  4. 1 FBV与CBV,前后端分离(初识),postman

    yuan的Blog:https://www.cnblogs.com/yuanchenqi/articles/8715364.html alice的Blog:https://www.cnblogs.co ...

  5. hdu 6065 RXD, tree and sequence

    题 OwO http://acm.hdu.edu.cn/showproblem.php?pid=6065 (2017 Multi-University Training Contest - Team ...

  6. 138企业邮箱pop/imap和smtp服务器地址

    如果客户端设置的是pop模式:接收邮件服务器(pop):pop.138mail.net ,端口号是110 (如果勾选了SSL,端口号则变为995)发送邮件服务器(smtp):smtp.138mail. ...

  7. JavaWeb-SpringSecurity图片验证ImageCode

    系列博文 项目已上传至guthub 传送门 JavaWeb-SpringSecurity初认识 传送门 JavaWeb-SpringSecurity在数据库中查询登陆用户 传送门 JavaWeb-Sp ...

  8. Java String字符串的不可变

    Java 通过把String类设计为final使类不可继承,将变量value设置为private并且是final的,且value没有setter方法,不可修改. 为什么这么设计: 1.字符串常量池的需 ...

  9. vue 打包部署到服务器上 配置nginx访问

    坑一 css,js资源引入不正确 webpack配置文件config/index.js 需要更改: 方法一 当部署到带有文件夹的项目中,这种绝对路径就会出现问题,因为把配置的static文件夹当成了根 ...

  10. (二)C语言之常量