【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进行了扩展,从而创造出一门新的程序设计语言,支持对象 ...
随机推荐
- C/C++编程笔记:inline函数的总结!C/C++新手值得收藏!
在c/c++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了inline修饰符,表示为内联函数. 栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间. 在系统下, ...
- 程序人生丨听说程序员是相当就能当的?BAT大牛当场就不乐意了!
有一种对软件开发者的偏见是:他们都是无趣的极客,是学校里的数学天才,每天都要在计算机屏幕前花费多个小时去写代码. 没错,开发者确实会在计算机屏幕前花费多个小时去写代码.但是,每天的工作中还有很多比写代 ...
- python之路第一节-pip的使用
第一次写博客,一边吃着旺仔冻痴一边学着python,爽~ 我之理解pip 首先,python封装好了大量的函数,这些函数存在各种各样的库中. 那么怎么去向我们可爱的pycharm等软件导入这些库呢,两 ...
- linux集群服务网络状态(netstat),服务端页面(图形字符页面)基本配置
Linux网络基础配置 yum -y install vim 安装vim 关闭的防火墙服务 iptables -F iptables -X iptables -Z systemctl s ...
- C调用C++代码
有时C程序里需要用到C++的类,但是C语言又不能直接调用类,这时需要把C++的类使用C接口封装后,再调用, 可以将封装后的C++代码编译成库文件,供C语言调用: 需要注意的是,封装的C++代码库文件是 ...
- myBatis源码解析-数据源篇(3)
前言:我们使用mybatis时,关于数据源的配置多使用如c3p0,druid等第三方的数据源.其实mybatis内置了数据源的实现,提供了连接数据库,池的功能.在分析了缓存和日志包的源码后,接下来分析 ...
- tensorflow 三种模型:ckpt、pb、pb-savemodel
1.CKPT 目录结构 checkpoint: model.ckpt-1000.index model.ckpt-1000.data-00000-of-00001 model.ckpt-1000.me ...
- LeetCode746 Min Cost Climbing Stairs(爬上楼梯的最小损失)
题目 On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed). Once you p ...
- ES6系列之项目中常用的新特性
ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...
- 轻轻松松学CSS:position
position属性表示元素的定位类型,在CSS布局中,position发挥着非常重要的作用,一些元素的布局就是用position完成的,鉴于此,本文结合一些小实例详细讲解一下. position属性 ...