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. Summer training #4

    D:找到两个数 一个是另一个的整数倍(1也算) 因为N是600000 调和级数为ln(n+1) 算一下 可以直接爆 #include <bits/stdc++.h> #include &l ...

  2. SQL语句 case ... when

    select 字段A, 字段B, CASE WHEN t.operate = 1 then 'aa'WHEN t.operate = 2 then 'bb'WHEN t.operate = 3 the ...

  3. main方法类 为何由AppClassLoader加载

    AppClassLoader AppClassLoader应用类加载器,又称系统类加载器,负责在JVM启动时加载来自命令java中的classpath或者java.class.path系统属性或者CL ...

  4. Tomcat基础知识

    介绍Tomcat之前先介绍下Java相关的知识. 各常见组件: 1.服务器(server):Tomcat的一个实例,通常一个JVM只能包含一个Tomcat实例:因此,一台物理服务器上可以在启动多个JV ...

  5. static和assets的区别

    assets和static两个都是用于存放静态资源文件. 放在static中的文件不会进行构建编译处理,也就不会压缩体积,在打包时效率会更高,但体积更大在服务器中就会占据更大的空间 放在assets中 ...

  6. div contenteditable 代替Textarea,做成Vue属性动态绑定

    前言 一般都是用Textarea 文本来编辑,但发现可以用 div contenteditable = “true”,这个属性来搞定 <div contenteditable=true plac ...

  7. [Functional Programming] Examples: When and Unless

    /** * When */ const _branch = (x) => { const result = (x && x.isPublic) ? dissoc('private ...

  8. Python之hashlib模块的使用

    hashlib模块主要的作用: 加密保护消息安全,常用的加密算法如MD5,SHA1等. 1.查看可用的算法有哪些 #!/usr/bin/env python # -*- coding: utf-8 - ...

  9. maven项目创7 配置分页插件

    页面编写顺序   首先确定是否拥有想要的pojo(对象实体类)———>dao层mybatis配置——>service层的接口及实现类——>controller(web下) 分页插件作 ...

  10. 日照学习提高班day4测试

    A 思路: 一看到这个题,他不仅要求输出字典序最小的串,还要满足两两不重复,所以我们可以先输出ababab...什么的,最后缀上要求的k-2种字母 坑点: 当然这样想是不完全的!该题是拥有许多特殊情况 ...