[golang note] 匿名组合
匿名组合
golang也提供了继承机制,但采用组合的文法,因此称为匿名组合。与其他语言不同, golang很清晰地展示出类的内存布局是怎样的。
• 非指针方式组合
▶ 基本语法
// 基类
type Base struct {
// 成员变量
} func (b *Base) 函数名(参数列表) (返回值列表) {
// 函数体
} // 派生类
type Derived struct {
Base
// 成员变量
} func (b *Derived) 函数名(参数列表) (返回值列表) {
// 函数体
}
▶ 继承规则
√ 在派生类没有改写基类的成员方法时,相应的成员方法被继承。
√ 派生类可以直接调用基类的成员方法,譬如基类有个成员方法为Base.Func(),那么Derived.Func()等同于Derived.Base.Func()
√ 倘若派生类的成员方法名与基类的成员方法名相同,那么基类方法将被覆盖或叫隐藏,譬如基类和派生类都有成员方法Func(),那么Derived.Func()将只能调用派生类的Func()方法,如果要调用基类版本,可以通过Derived.Base.Func()来调用。
▪ 示例如下
package main
import "fmt"
type Base struct {
}
func (b *Base) Func1() {
fmt.Println("Base.Func1() was invoked!")
}
func (b *Base) Func2() {
fmt.Println("Base.Func2() was invoked!")
}
type Derived struct {
Base
}
func (d *Derived) Func2() {
fmt.Println("Derived.Func2() was invoked!")
}
func (d *Derived) Func3() {
fmt.Println("Derived.Func3() was invoked!")
}
func main() {
d := &Derived{}
d.Func1() // Base.Func1() was invoked!
d.Base.Func1() // Base.Func1() was invoked!
d.Func2() // Derived.Func2() was invoked!
d.Base.Func2() // Base.Func2() was invoked!
d.Func3() // Derived.Func3() was invoked!
}
▶ 内存布局
√ golang很清晰地展示类的内存布局是怎样的,即Base的位置即基类成员展开的位置。
√ golang还可以随心所欲地修改内存布局,即Base的位置可以出现在派生类的任何位置。
▪ 示例如下
package main
import "fmt"
type Base struct {
BaseName string
}
func (b *Base) PrintName() {
fmt.Println(b.BaseName)
}
type Derived struct {
DerivedName string
Base
}
func (d *Derived) PrintName() {
fmt.Println(d.DerivedName)
}
func main() {
d := &Derived{}
d.BaseName = "BaseStruct"
d.DerivedName = "DerivedStruct"
d.Base.PrintName() // BaseStruct
d.PrintName() // DerivedStruct
}
• 指针方式组合
▶ 基本语法
// 基类
type Base struct {
// 成员变量
} func (b *Base) 函数名(参数列表) (返回值列表) {
// 函数体
} // 派生类
type Derived struct {
*Base
// 成员变量
} func (b *Derived) 函数名(参数列表) (返回值列表) {
// 函数体
}
▶ 继承规则
√ 基类采用指针方式的组合,依然具有派生的效果,只是派生类创建实例的时候需要外部提供一个基类实例的指针。
√ 其他规则与非指针方式组合一致。
▪ 示例如下
package main import (
"fmt"
"log"
"os"
) type MyJob struct {
Command string
*log.Logger
}
func (job *MyJob) Start() {
job.Println("job started!") // job.Logger.Println fmt.Println(job.Command) job.Println("job finished!") // job.Logger.Println
} func main() {
logFile, err := os.OpenFile("./job.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, )
if err != nil {
fmt.Println("%s", err.Error())
return
}
defer logFile.Close() logger := log.New(logFile, "[info]", log.Ldate|log.Ltime|log.Llongfile)
job := MyJob{"programming", logger} job.Start()
job.Println("test finished!") // job.Logger.Println
}
在经过合适的赋值后,MyJob类型的所有成员方法可以很方便地借用所有log.Logger提供的方法。这对于MyJob的实现者来说,根本就不用意识到log.Logger类型的存在,这就是匿名组合的一个魅力所在。
一些总结
• 名字覆盖
上面说明了派生类成员方法名与基类成员方法名相同时基类方法将被覆盖的情况,这对于成员变量名来说,规则也是一致的。
package main
import "fmt"
type Base struct {
Name string
}
type Derived struct {
Base
Name string
}
func main() {
d := &Derived{}
d.Name = "Derived"
d.Base.Name = "Base"
fmt.Println(d.Name) // Derived
fmt.Println(d.Base.Name) // Base
}
• 名字冲突
匿名组合相当于以其类型名称(去掉包名部分)作为成员变量的名字。那么按此规则,类型中如果存在两个同名的成员,即使类型不同,但我们预期会收到编译错误。
package main
import "log"
type Logger struct {
Level int
}
type MyJob struct {
*Logger
Name string
*log.Logger // duplicate field Logger
}
func main() {
job := &MyJob{}
}
[golang note] 匿名组合的更多相关文章
- [golang note] 接口使用
侵入式接口 √ 在其他一些编程语言中,接口主要是作为不同组件之间的契约存在,即规定双方交互的规约. √ 对契约的实现是强制的,即必须确保用户的确实现了该接口,而实现一个接口,需要从该接口继承. √ 如 ...
- go的匿名组合
golang也提供了继承机制,但采用组合的文法,因此称为匿名组合.与其他语言不同, golang很清晰地展示出类的内存布局是怎样的. 一 非指针方式的组合 1)基本语法 type base stru ...
- [golang note] 函数定义
普通函数定义 √ golang函数基本组成:关键字func.函数名.参数列表.返回值.函数体和返回语句. • 语法如下 func 函数名(参数列表) (返回值列表) { // 函数体 } • 示例如下 ...
- Golang函数-匿名函数与闭包函数
Golang函数-匿名函数与闭包函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.
- golang 使用匿名结构体的问题
golang允许使用匿名结构体,形如 type Test struct { param1 struct { param2 string } } 一般在使用的时候可以直接这样初始化 a := Test{ ...
- 【玩转Golang】 通过组合嵌入实现代码复用
应用开发中的一个常见情景,为了避免简单重复,需要在基类中实现共用代码,着同样有助于后期维护. 如果在以往的支持类继承的语言中,比如c++,Java,c#等,这很简单!可是go不支持继承,只能mixin ...
- [golang note] 协程通信
channel基本语法 • channel介绍 √ golang社区口号:不要通过共享内存来通信,而应该通过通信来共享内存. √ golang提供一种基于消息机制而非共享内存的通信模型.消息机制认为每 ...
- Golang之匿名函数和闭包
Go语言支持匿名函数,即函数可以像普通变量一样被传递或使用. 使用方法如下: main.go package main import ( "fmt" ) func main() { ...
- [golang note] 类型系统
值和引用 • 值语义和引用语义 值语义和引用语义的差别在于赋值: b = a b.Modify() 如果b的修改不会影响a的值,那么属于值类型,否则属于引用类型. • 值类型和引用类型 √ 引用类型一 ...
随机推荐
- 欧拉函数 & 【POJ】2478 Farey Sequence & 【HDU】2824 The Euler function
http://poj.org/problem?id=2478 http://acm.hdu.edu.cn/showproblem.php?pid=2824 欧拉函数模板裸题,有两种方法求出所有的欧拉函 ...
- 【HDU】3622 Bomb Game(2-SAT)
http://acm.hdu.edu.cn/showproblem.php?pid=3622 又是各种逗.. 2-SAT是一种二元约束,每个点可以置于两种状态,但只能处于一种状态,然后图是否有解就是2 ...
- Java设计模式菜鸟系列(十)模板方法模式建模与实现
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39806973 模板方法模式(Template Method):在一个方法中定义了一个算法的 ...
- PHPExcel IE导出乱码问题
引用改网站介绍:http://blog.chinaunix.net/uid-22414998-id-113450.html PHPExcel是微软认证的一个PHP操作Excel表格的类库,功能强大,所 ...
- ThinkPHP项目笔记之RBAC(权限)下篇
接着谈谈:添加用户以及用户管理列表 e.添加用户
- Mac终端使用mysql
1.安装完mysql后给mysql命别名 alias mysql=/usr/local/mysql/bin/mysql aliasmysqladmin=/usr/local/mysql/bin/mys ...
- 用公式编辑器编辑n元乘积的方法
在数学中经常会出现很多个元素进行求和或者是乘积的情况,但是在整个数学过程中,不可能将所有的元素都写出来,这样很费时费力同时过程也很赘余,不能很好地理解其中的过程,因此数学中对于这一类的多元相加或者相乘 ...
- 移动ChemDraw结构有什么方法
ChemDraw软件是一款比较常见的化学绘图软件,化学专业的领域的人常常会用到它.本教程主要是针对新手用户,让其了解一些ChemDraw的一些基本操作,以便其能尽快上手早日用到工作中.下面我们就来给大 ...
- DBA面试题及解答
一:SQL tuning 类 1:列举几种表连接方式答:merge join,hash join,nested loop Hash join散列连接是CBO 做大数据集连接时的常用方式,优化器使用两个 ...
- 华为 进入和退出Fastboot、eRecovery和Recovery升级模式
手机关机状态下,可以进入Fastboot/eRecovery / Recovery/升级这几种模式: 需要连接电脑:Fastboot模式:长按音量下键+电源键.eRecovery 模式:长按音量上键+ ...