Go语言之嵌入类型

简介:

嵌入类型,或者嵌套类型,这是一种可以把已有的类型声明在新的类型里的一种方式,这种功能对代码复用非常重要。


在其他语言中,有继承可以做同样的事情,但是在Go语言中,没有继承的概念。Go提倡的代码复用的方式是组合,所以这也是嵌入类型的意义所在。组合而不是继承,所以Go才会更灵活。


type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}


type ReadWriter interface {
    Reader
    Writer
}

type ReadCloser interface {
    Reader
    Closer
}

type WriteCloser interface {
    Writer
    Closer
}


以上是标准库io包里我们常用的接口,可以看到ReadWriter接口是嵌入ReaderReader接口而组合成的新接口,这样我们就不用重复地定义被嵌入接口里的方法,直接通过嵌入就可以了。嵌入类型同样适用于结构体类型,我们再来看个例子:


type user struct {
    name string
    email string

}

type admin struct {
    user
    level string
}


嵌入后,被嵌入的类型称之为内部类型,新定义的类型称之为外部类型。这里user就是内部类型,而admin是外部类型。


通过嵌入类型,与内部类型相关联的所有字段、方法、标志符等,都会被外包类型所拥有。就像外部类型自己的一样,这就达到了代码快捷复用组合的目的,而且定义非常简单,只需声明这个类型的名字就可以了。


同时,外部类型还可以添加自己的方法、字段属性等,可以很方便地扩展外部类型的功能。


func main() {
    ad:=admin{user{"张三","zhangsan@flysnow.org"},"管理员"}
    fmt.Println("可以直接调用,名字为:",ad.name)
    fmt.Println("也可以通过内部类型调用,名字为:",ad.user.name)
    fmt.Println("但是新增加的属性只能直接调用,级别为:",ad.level)
}


以上是嵌入类型的使用。可以看到,我们在初始化的时候,采用的是字面值的方式。所以要按其定义的结构进行初始化,先初始化user这个内部类型的,再初始化新增的level 属性。


对于内部类型的属性和方法访问,我们可以用外部类型直接访问,也可以通过内部类型进行访问;但是我们为外部类型新增的方法属性字段,只能使用外部类型访问,因为内部类型没有这些。


当然,外部类型也可以声明同名的字段或者方法,来覆盖内部类型的,这种情况方法比较多,我们以方法为例。


func main() {
    ad:=admin{user{"张三","zhangsan@flysnow.org"},"管理员"}
    ad.user.sayHello()
    ad.sayHello()
}

type user struct {
    name string
    email string

}

type admin struct {
    user
    level string
}

func (u user) sayHello(){
    fmt.Println("Hello,i am a user")
}

func (a admin) sayHello(){
    fmt.Println("Hello,i am a admin")
}


内部类型user有一个sayHello方法,外部类型对其进行了覆盖,同名重写sayHello,然后我们在main方法里分别访问这两个类型的方法,打印输出:


Hello,i am a user
Hello,i am a admin


从输出中看,方法sayHello被成功覆盖了。


嵌入类型的强大,还体现在:如果内部类型实现了某个接口,那么外部类型也被认为实现了这个接口。我们稍微改造下例子看下。


func main() {
    ad:=admin{user{"张三","zhangsan@flysnow.org"},"管理员"}
    sayHello(ad.user)//使用user作为参数
    sayHello(ad)//使用admin作为参数
}


type Hello interface {
    hello()
}

func (u user) hello(){
    fmt.Println("Hello,i am a user")
}

func sayHello(h Hello){
    h.hello()
}


这个例子原来的结构体类型useradmin的定义不变,新增了一个接口Hello,然后让user类型实现这个接口,最后我们定义了一个sayHello方法,它接受一个Hello接口类型的参数。最终我们在main函数演示的时候,发现不管是user类型,还是admin类型作为参数传递给sayHello方法的时候,都可以正常调用。


这里就可以说明admin实现了接口Hello。但是我们又没有显示声明类型admin实现,所以这个实现是通过内部类型user实现的;因为admin包含了user所有的方法函数,所以也就实现了接口Hello


当然外部类型也可以重新实现,只需要像上面例子一样覆盖同名的方法即可。这里要说明的是,不管我们如何同名覆盖,都不会影响内部类型,我们还可以通过访问内部类型来访问它的方法、属性字段等。


嵌入类型的定义,是Go为了方便我们扩展或者修改已有类型的行为,是为了宣传组合这个概念而设计的,所以我们经常使用组合,灵活运用组合,扩展出更多的我们需要的类型结构



本文转自 baby神 51CTO博客,原文链接:xxxxhttp://blog.51cto.com/babyshen/1923492xxx,如需转载请自行联系原作者

相关文章
|
7月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
7月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
1月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
1月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
2月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
2月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
208 0
|
3月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
4月前
|
存储 JSON Go
Go语言之空接口与类型断言
本文介绍了 Go 语言中空接口(`interface{}`)和类型断言的核心概念及其应用。空接口可存储任意类型数据,适用于通用函数、动态数据结构与 JSON 解析等场景;类型断言用于将接口变量还原为具体类型,推荐使用带 `ok` 的写法以避免程序崩溃。此外,文章通过示例讲解了 `type switch` 类型判断与 JSON 处理技巧,并总结了空接口的注意事项,强调滥用可能导致类型安全性降低。内容深入浅出,帮助开发者灵活运用这些特性。
102 15
|
4月前
|
算法 Go
Go语言模拟集合类型-《Go语言实战指南》
在 Go 语言中,虽然没有内建的集合(Set)类型,但可以通过 `map` 实现其功能。常用方式包括 `map[T]bool` 和更节省内存的 `map[T]struct{}`。前者以布尔值表示元素存在性,后者利用零内存开销的空结构体。文章介绍了集合的基本操作(添加、删除、判断、遍历),并通过封装示例展示如何创建自定义 Set 类型。这种实现方式适用于去重、唯一标记及集合运算等场景,简洁高效且易于扩展。
|
4月前
|
分布式计算 Go C++
初探Go语言RPC编程手法
总的来说,Go语言的RPC编程是一种强大的工具,让分布式计算变得简单如同本地计算。如果你还没有试过,不妨挑战一下这个新的编程领域,你可能会发现新的世界。
106 10