【Go语言入门系列】(八)Go语言是不是面向对象语言?
【Go语言入门系列】前面的文章:
1. Go是面向对象的语言吗?
在【Go语言入门系列】(七)如何使用Go的方法?这一文中已经介绍了方法的概念,但这个方法实际上并不是面向对象中的方法。方法实际上是用户给其定义的类型的增加的新行为,实际上也是个函数。
关于这个问题,官方文档中有回答:
Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of “interface” in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain, “unboxed” integers. They are not restricted to structs (classes).
Also, the lack of a type hierarchy makes “objects” in Go feel much more lightweight than in languages such as C++ or Java.
既是也不是。尽管Go拥有类型和方法,也允许面向对象风格的编程,但它没有类型层级。 在Go中“接口”的概念提供了不同的方法,我们相信它易于使用且在某些方面更通用。 也有一些在其它类型中嵌入类型的方法,来提供类似(而非完全相同)的东西进行子类化。 此外,Go中的方法比C++或Java中的更通用:它们可被定义为任何种类的数据。 甚至是像普通的“未装箱”整数这样的内建类型。它们并不受结构(类)的限制。
此外,类型层级的缺失也使Go中的“对象”感觉起来比C++或Java的更轻量级。
有了这个回答,下面介绍的“继承”和“重写”的概念并不是严格的面向对象中的继承和重写的概念。这里只借用这两个名词来表示Go的两种特性。
2.“继承”
在面向对象中,继承是子类和父类之间的关系,子类会继承父类的公有成员变量和成员方法。
前面提到过,Go允许面向对象风格的编程。那Go如何“继承”呢?
2.1.“继承”字段
在【Go语言入门系列】(五)指针和结构体的使用这一文中,介绍了匿名字段(也叫嵌入字段):
package main
import "fmt"
type people struct {
name string
age int
}
type student struct {
people
school string
}
func (s student) say() {
fmt.Printf("我是%s,今年%d岁了,在%s上学。", s.name, s.age, s.school)
}
func main() {
stu := student{people{"行小观", 1}, "阳光小学"}
stu.say()
}
运行:
我是行小观,今年1岁了,在阳光小学上学
结构体student中有匿名字段people,所以student就有了people的name和age字段。当匿名字段是一个结构体时,那么该结构体的全部字段都会被引入当前的结构体中。这是不是很像面向对象中的继承?子类继承父类的公有成员变量。
考虑下面一个问题,如果student和people中都有name字段,那么访问时,Go语言是如何处理的?
package main
import "fmt"
type people struct {
name string //人名
age int
}
type student struct {
people
name string //学生名
school string
}
func main() {
stu := student{people{"李二狗", 1}, "李向前", "阳光学校"}
fmt.Println(stu.name) //李向前
fmt.Println(stu.people.name) //李二狗
}
此时就出现了字段冲突,Go会先访问外层的字段。比如,stu.name是李向前(外层),stu.people.name是李二狗(内层)。
2.2.“继承”方法
我们通过接收者把函数绑定到结构体类型上,这样的函数称为方法,方法就在概念上属于了接收者对应的结构体。
上面通过结构体中匿名字段实现了“继承”字段的效果,对于方法来说,同样可以。下面是一个实例:
package main
import "fmt"
type people struct {
name string
age int
}
type student struct {
people
school string
}
type programmer struct {
people
language string
}
func (p people) say() {
fmt.Printf("我是%s,今年%d岁了,和我一起学习Go语言吧!\n", p.name, p.age)
}
func main() {
stu := student{people{"行小观", 1}, "阳光小学"}
stu.say()
prom := programmer{people{"张三", 1}, "蓝天建筑有限公司"}
prom.say()
}
运行:
我是行小观,今年1岁了,和我一起学习Go语言吧!
我是张三,今年1岁了,和我一起学习Go语言吧!
say()方法的接收者是people类型,而结构体student和programmer中都有匿名字段people,所以stu和prom都能调用say()方法。这是不是很像面向对象语言中子类继承父类的公有方法?
3. “重写”
3.1. “重写”字段
前面已经介绍了如果结构体和作为其字段的结构体的字段冲突了如何处理。有了这个特性,我们就可以“重写”字段。
package main
import "fmt"
type people struct {
name string //乳名
age int
}
type student struct {
people
name string //大名
school string
}
func (s student) say() {
fmt.Printf("我是%s,今年%d岁了,和我一起学习Go语言吧!\n", s.name, s.age)
}
func main() {
stu := student{people{"李二狗", 1}, "李向前","阳光小学"}
stu.say()
}
运行:
我是李向前,今年1岁了,和我一起学习Go语言吧!
李二狗是乳名,李向前才是大名。自我介绍时说的是大名李向前。如果需要乳名,则使用stu.people.name。
3.2.“重写”方法
下面是一个实例:
package main
import "fmt"
type people struct {
name string
age int
}
type student struct {
people
school string
}
type programmer struct {
people
language string
}
func (p people) say() { //people的say方法
fmt.Printf("我是%s,今年%d岁了,和我一起学习Go语言吧!\n", p.name, p.age)
}
func (s student) say() { //student重写people的say方法
fmt.Printf("我是%s,是个学生,今年%d岁了,我在%s上学!\n", s.name, s.age, s.school)
}
func (p programmer) say() { //programmer重写people的say方法
fmt.Printf("我是%s,是个程序员,今年%d岁了,我使用%s语言!\n", p.name, p.age, p.language)
}
func main() {
stu := student{people{"李向前", 1}, "阳光小学"}
stu.say()
prmger := programmer{people{"张三", 1}, "Go"}
prmger.say()
}
运行:
我是李向前,是个学生,今年1岁了,我在阳光小学上学!
我是张三,是个程序员,今年1岁了,我使用Go语言!
student和programmer“继承”了people的say()方法,但是不合适,于是各自“重写”了say()方法。
看到这里,你就理解了官方文档中的那两句话是什么意思了。
“尽管Go拥有类型和方法,也允许面向对象风格的编程,但它没有类型层级”
“类型层级的缺失也使Go中的“对象”感觉起来比C++或Java的更轻量级”
作者简介
我是行小观,我会在公众号『行人观学』中持续更新Java、Go、数据结构和算法、计算机基础等相关文章。
本文章已收录进系列文章「Go语言入门系列」,本系列从Go语言基础开始介绍,适合从零开始的初学者。
欢迎关注,我们一起踏上编程的行程。
如有错误,还请指正。
【Go语言入门系列】(八)Go语言是不是面向对象语言?的更多相关文章
- 【Go语言入门系列】Go语言工作目录介绍及命令工具的使用
[Go语言入门系列]前面的文章: [保姆级教程]手把手教你进行Go语言环境安装及相关VSCode配置 [Go语言入门系列](八)Go语言是不是面向对象语言? [Go语言入门系列](九)写这些就是为了搞 ...
- C语言高速入门系列(八)
C语言高速入门系列(八) C语言位运算与文件 本章引言: 在不知不觉中我们的C高速入门系列已经慢慢地接近尾声了,而在这一节中,我们会对 C语言中的位运算和文件进行解析,相信这两章对于一些人来说是陌生的 ...
- 【Go语言入门系列】(九)写这些就是为了搞懂怎么用接口
[Go语言入门系列]前面的文章: [Go语言入门系列](六)再探函数 [Go语言入门系列](七)如何使用Go的方法? [Go语言入门系列](八)Go语言是不是面向对象语言? 1. 引入例子 如果你使用 ...
- Go语言入门系列(四)之map的使用
本系列前面的文章: Go语言入门系列(一)之Go的安装和使用 Go语言入门系列(二)之基础语法总结 Go语言入门系列(三)之数组和切片 1. 声明 map是一种映射,可以将键(key)映射到值(val ...
- Go语言入门系列(五)之指针和结构体的使用
Go语言入门系列前面的文章: Go语言入门系列(二)之基础语法总结 Go语言入门系列(三)之数组和切片 Go语言入门系列(四)之map的使用 1. 指针 如果你使用过C或C++,那你肯定对指针这个概念 ...
- Go语言入门系列(六)之再探函数
Go语言入门系列前面的文章: Go语言入门系列(三)之数组和切片 Go语言入门系列(四)之map的使用 Go语言入门系列(五)之指针和结构体的使用 在Go语言入门系列(二)之基础语法总结这篇文章中已经 ...
- 【Go语言入门系列】(七)如何使用Go的方法?
[Go语言入门系列]前面的文章: [Go语言入门系列](四)之map的使用 [Go语言入门系列](五)之指针和结构体的使用 [Go语言入门系列](六)之再探函数 本文介绍Go语言的方法的使用. 1. ...
- 微软云平台windows azure入门系列八课程
微软云平台windows azure入门系列八课程: Windows Azure入门教学系列 (一): 创建第一个WebRole程序与部署 Windows Azure入门教学系列 (二): 创建第一个 ...
- 一.OC基础之:1,OC语言的前世今生 ,2,OC语言入门,3,OC语言与C的差异,4,面向对象,5,类和对象的抽象关系,6,类的代码创建,7,类的成员组成及访问
1,OC语言的前世今生 , 一, 在20世纪80年代早期,布莱德.麦克(Brad Cox)设计了OC语言,它在C语言的基础上增加了一层,这意味着对C进行了扩展,从而创造出一门新的程序设计语言,支持对象 ...
随机推荐
- CF R638 div2 F Phoenix and Memory 贪心 线段树 构造 Hall定理
LINK:Phoenix and Memory 这场比赛标题好评 都是以凤凰这个单词开头的 有凤来仪吧. 其实和Hall定理关系不大. 不过这个定理有的时候会由于 先简述一下. 对于一张二分图 左边集 ...
- “商家参数格式有误”应用切微信H5支付完美解决方案
一.业务场景发生 最近在跟一些合作公司作业务对接,在对方的APP中接入我们的H5支付,包括微信和支付宝. 那就开搞,进展顺利,貌似一切都在掌握之中,给到对方一个链接即可调起支付.形如: https:/ ...
- linux之SAMBA共享目录服务端架设
samba 共享目录 1.SAMBA服务概述 协议 监听端口137 架构 samba:Linux系统的一种文件共享程序服务 通常在主机文件共享的应用场景中,由于文件系统的差异化,Windows和L ...
- 2020牛客暑期多校训练营(第八场)K-Kabaleo Lite题解
K-Kabaleo Lite 题目大意: 给出每种菜品的利润以及碟数,要求我们给每个客人至少一碟菜,要求从1号菜品开始给,给的菜品的号码是连续的,每个客人同号码的菜都只能给一碟.求能招待客人的最大数量 ...
- windows 下部署 .netcore 到 docker
前面我们演示了如何将 Asp.Net Core 程序部署到 iis 和 部署到 windows 服务.其实前面的都是铺垫,如何将 Asp.Net Core 站点部署到 docker 才是这个系列文章的 ...
- OGG复制进程延迟高,优化方法一(使用索引)
日常运维过程中,可能发现OGG同步进程延迟很高: 本篇介绍其中的一种方式. OGG复制进程,或者说同步进程及通过解析ogg trail文件,输出dml语句,在目标库执行dml操作,那么延迟高可能性其一 ...
- MySQL数据库——查询数据
增加数据: insert into "表名" values( '字段'',字段'); 或insert into '表名'( '字段'',字段') values( '字段'',字段 ...
- vue报错vue-router.esm.js?8c4f:2007 Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated"}
今天在写vue项目配置好路由点击菜单时,突然在控制台报错. 错误信息如下: Uncaught (in promise) NavigationDuplicated {_name: "Navig ...
- Android 重写物理返回键,在h5页面中返回上一个界面
实现:Activity中放置webview,跳转到h5界面,点击返回键,不退出h5界面,而是返回上一个h5界面 /** * 改写物理按键--返回的逻辑,希望浏览的网页后退而不是退出浏览器 * @par ...
- 非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭
非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭 题目描述 由于各种原因,桐人现在被困在\(Under World\)(以下简称\(UW\))中,而\(UW\)马上 要迎来最终的压力测试--魔界 ...