专栏首页TechFlowgolang | Go语言入门教程——结构体初始化与继承

golang | Go语言入门教程——结构体初始化与继承

今天是golang专题第10篇文章,我们继续来看golang当中的面向对象部分。

在上一篇文章当中我们一起学习了怎么创建一个结构体,以及怎么给结构体定义函数,还有函数接收者的使用。今天我们来学习一下结构体本身的一些使用方法。

初始化

在golang当中结构体初始化的方法有四种

new关键字

我们可以通过new关键字来创建一个结构体的实例,这种方法和其他语言比较类似,这样会得到一个空结构体指针,当中所有的字段全部填充它类型对应的零值。比如int就对应0,float对应0.0,如果是其他结构体则对应nil。

type Point struct {
 x int
 y int
}

func main() {
 var p *Point = new(Point)
 fmt.Print(p)
}

从这段代码当中我们可以看到,new函数返回的是一个结构体指针,而不是结构体的值。一般我们很少用new关键字,而是直接通过结构体加花括号的方式来初始化。

结构体名称

相比于使用new关键字,我们更常用的是通过结构体名称加上花括号的方式来进行初始化。

如果我们不再花括号当中填写参数的话,那么同样会得到一个填充了零值的结构体。结构体当中的所有属性都会被赋予这个类型对应的零值。

type Point struct {
 x int
 y int
}

func main() {
    p := Point{}
 fmt.Print(p)
}

如果我们想要初始化一个结构体的指针,我们只需要在结构体名称之前加上取地址符&即可。所以创建一个结构体指针可以这样:

func main() {
    p := &Point{}
 fmt.Print(p)
}

golang当中取地址符和声明指针的关键字和C语言是一样的,对于熟悉C语言的同学来说,这应该并不困难。

我们在花括号当中填充参数,这些参数会按照顺序填充到结构体的属性当中。为了防止混淆,我们也可以在值之前加上它对应的属性名称。

func main() {
    p := &Point{0, 0}
    k := &Point{x: 0, y: 10}
 fmt.Print(p)
}

继承

很多人不喜欢golang的主要原因就是觉得golang阉割了面向对象的很多功能之后,导致开发的时候束手束脚,总觉得不太方便。其中为人诟病得比较厉害的就是继承,觉得golang当中没有继承,写有依赖的结构体的时候非常蛋疼。

我之前一度也这么觉得,最近仔细研究了其中的道道之后,发现我错了,golang当中也是有继承的,不过它实现的方式和我们一般理解上的不太一样,有一些出其不意。所以我们拿正统的眼光去看它总会觉得它不伦不类,哪里不太对劲。这种感觉有点像是武侠小说里名门正派看旁门左派的感觉,但旁门左派并不代表就不行,也有能打的。

在我们正常的映像当中,我们实现继承就应该是标明当前这个类的父类是哪个类,这样底层编译器自动将父类的属性和方法都拷贝一份到子类当中来。加上private、public等关键词束缚,来控制一下什么方法和属性可以被继承什么不可以就完美了。

我们用Python举个例子,Python当中对于继承的定义已经非常简洁了,实现起来大概是这样的:

class A:
    pass

class B(A):
    pass

直接在类名的后面就加上继承的信息,实际上绝大多数主流语言也都是这么干的。但golang不是,它做了一件什么事呢?它将父类作为变量定义在了子类的里面,严格说起来这已经不是继承了,算是一种奇怪的组合,但它起到的功能类似于继承。

我光说理解起来很累,我们来看个例子,比如我们当下有一个父类(结构体),它有两个结构体方法:

type Father struct {
    Name string
}

func(entity Father) Hello() {...}
func(entity Father) World() {...}

现在我们要创建一个它的子类,需要把Father这个结构体填进去,变成其中一个成员变量

type Child struct {
    Father
    ...
}

那有了这么一个看起来很奇怪的子类之后,我们怎么调用父类的方法呢?

答案是直接调用

child := Child{}
child.Hello()

按照我们的理解,由于父类是子类当中的一个成员,所以我们想要调用父类的方法,应该写成child.Father.Hello()才对。但实际上golang替我们做了相关的优化,我们直接调用方法,也可以找到父类当中的方法。

如果我们要改写父类的方法也不困难,我们可以这样操作:

func (entity Child) World() {
    entity.Father.World()
    ...
}

如此,父类当中的World方法就被Child改写了,这样就完成了继承当中对父类函数的改写。

总结

到这里,关于golang当中结构体初始化与继承的介绍就结束了。不知道大家看完这篇有什么样的感受,我最大的感觉是好像没有第一次看到它的时候那么难以接受了XD。

据说这个设计和C++当中的虚基类的概念非常接近,但是虚基类非常难以理解(比如我就没能理解),以至于许多C++工程师会自动忽略它的存在。相比之下,golang的这种设计要容易理解得多。虽然看起来麻烦,但是理解起来也并不困难。

本文分享自微信公众号 - TechFlow(techflow2019),作者:梁唐

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Golang简单入门教程——函数进阶篇

    我们在之前的时候已经介绍过了函数的基本用法,知道了怎么样设计或者是定义一个函数,以及怎么样调用一个函数,还了解了defer的用法。今天这篇文章我们来继续深入这个...

    TechFlow-承志
  • Golang入门教程——面向对象篇

    今天是golang专题的第9篇文章,我们一起来看看golang当中的面向对象的部分。

    TechFlow-承志
  • Python——详解collections工具库,一篇文章全搞定

    今天为大家介绍Python当中一个很好用也是很基础的工具库,叫做collections。

    TechFlow-承志
  • [python][matlab]使用py

    在做实验的时候,需要用到python和matlab工具来进行不同的处理,比如在run神经网络的时候,需要使用pytorch框架得到网络的各个参数,在得到参数后需...

    py3study
  • python,pexpect登录ssh并

    wget http://jaist.dl.sourceforge.net/project/pexpect/pexpect/Release%202.3/pexpe...

    py3study
  • python 舆情分析 nlp主题分析 (3) --gensim库的简单使用

    python 舆情分析 nlp主题分析 (1) 待续: https://www.cnblogs.com/cycxtz/p/13663895.html

    forxtz
  • 跳转语句continue和break

    /*         break:结束本轮循环         continue:跳出本次循环,执行下次循环         */      使用contin...

    十月梦想
  • 中国电子学会-腾讯Robotics X犀牛鸟专项研究计划(2020)评审结果

    ? 为了促进机器人领域的前沿问题研究和关键技术研发,推动产学研合作,培养创新人才,2020年6月,中国电子学会与腾讯共同发布中国电子学会-腾讯Robotics...

    腾讯高校合作
  • 管理|从0开始组建一支研发团队(一)

    黄小怪
  • Huawei Pay:开放API接口,支持北京等城市一卡通

    据Jason介绍,目前支持Huawei Pay交通卡功能的华为终端设备已经达到22款,Huawei Pay已支持北京、上海、深圳、广州(岭南通)、广西、武汉、...

    BestSDK

扫码关注云+社区

领取腾讯云代金券