byte数组初始化_Go 语言面向对象教程 —— 类的定义、初始化和成员方法

先看看 Go 中的类型系统。

对于面向对象编程的支持,Go 语言的实现可以说是完全颠覆了以往我们对面向对象编程的认知,下面我们先通过对 Go 语言类型系统的介绍让你有一个整体的认知。

Go 语言面向对象编程设计得简洁而优雅。

简洁之处在于,Go 语言并没有沿袭传统面向对象编程中的诸多概念,比如类的继承、接口的实现、构造函数和析构函数、隐藏的 this 指针等,也没有 public、protected、private 之类的可见性修饰符。

优雅之处在于,Go 语言对面向对象编程的支持是语言类型系统中的天然组成部分,整个类型系统通过接口串联,浑然一体。

很少有编程类的书谈及类型系统这个话题,实际上类型系统才是一门编程语言的地基,它的地位至关重要。因此,这里我们将从类型系统入手介绍 Go 语言的面向对象编程特性。

顾名思义,类型系统是指一个语言的类型体系结构。一个典型的类型系统通常包含如下基本内容:

  • 基础类型,如 byteintboolfloatstring 等;

  • 复合类型,如数组、切片、 字典、结构体、指针等;

  • 可以指向任意对象的类型(Any 类型);

  • 值语义和引用语义;

  • 面向对象,即所有具备面向对象特征(比如成员方法)的类型;

  • 接口。

类型系统描述的是这些内容在一个语言中如何被关联。因为 Java 语言自诞生以来被称为最纯正的面向对象语言,所以我们就先以 Java 语言为例讲一讲类型系统。

在 Java 语言中,存在两套完全独立的类型系统:一套是值类型系统,主要是基本类型,如 byteintbooleanchardouble 等,这些类型基于值语义;一套是以 Object 类型为根的对象类型系统,这些类型可以定义成员变量和成员方法,可以有虚函数,基于引用语义,只允许在堆上创建(通过使用关键字 new)。Java 语言中的 Any 类型就是整个对象类型系统的根 —— java.lang.Object 类型,只有对象类型系统中的实例才可以被 Any类型引用。值类型想要被 Any 类型引用,需要装箱 (boxing)过程,比如 int 类型需要装箱成为 Integer 类型。另外,只有对象类型系统中的类型才可以实现接口,具体方法是让该类型从要实现的接口继承。

相比之下,Go 语言中的大多数类型都是值语义,并且都可以包含对应的操作方法。在需要的时候,你可以给任何类型(包括内置类型)增加新方法。而在实现某个接口时,无需从该接口继承(事实上,Go 语言根本就不支持面向对象思想中的继承、实现语法),只需要实现该接口要求的所有方法即可。任何类型都可以被 Any 类型引用。在 Go 语言中,Any 类型就是空接口,即 interface{}

注:这里的值语义和引用语义等价于之前介绍类型时提到的值类型和引用类型。

接下来我们会对 Go 语言类型系统的特点逐一进行讲解。

声明:Go 语言类型系统篇内容节选自自《Go 语言编程》(许式伟等著)中类型系统一节。

接下来,我们就与 Go 语言面向对象编程相关的特性展开介绍。

类的定义和初始化

Go 语言的面向对象编程与我们之前所熟悉的 PHP、Java 那一套完全不同,没有 classextendsimplements之类的关键字和相应的概念,而是借助结构体来实现类的声明,比如要定义一个学生类,可以这么做:

type Student struct {    id uint    name string    male bool    score float64}

类名为 Student,并且包含了 idnamemalescore 四个属性,Go 语言中也不支持构造函数、析构函数,取而代之地,可以通过定义形如 NewXXX 这样的全局函数(首字母大写)作为类的初始化函数:

func NewStudent(id uint, name string, male bool, score float64) *Student {    return &Student{id, name, male, score}}

在这个函数中,我们通过传入的属性字段对 Student 类进行初始化并返回一个指向该类的指针,除此之外,还可以初始化指定字段:

func NewStudent(id uint, name string, score float64) *Student {    return &Student{id: id, name:name, score:score}}

在 Go 语言中,未进行显式初始化的变量都会被初始化为该类型的零值,例如 bool 类型的零值为 falseint 类型的零值为 0,string 类型的零值为空字符串,float 类型的零值为 0.0。

然后我们可以在 main() 函数中调用这个 NewStudent 函数对 Student 类进行初始化:

student := NewStudent(1, "学院君", 100)fmt.Println(student)

上述代码的打印结果如下:

&{1 学院君 false 100}

为类添加成员方法

由于 Go 语言不支持 class 这样的代码块,要为 Go 类添加成员方法,需要在 func 和方法名之间添加方法所属的类型声明(有的地方将其称之为接收者声明),以 Student 类为例,要为其添加返回 name 值的方法,可以这么做:

func (s Student) GetName() string  {    return s.name}

然后我们就可以在初始化 Student 后,通过 GetName() 方法获取 name 值:

student := NewStudent(1, "学院君", 100)fmt.Println("Name:", student.GetName())

可以看到,我们通过在函数中增加接收者声明的方式定义了函数所归属的类型,这个时候,函数就不再是普通的函数,而是类的成员方法了,然后可以在成员方法中,通过声明的类型变量来访问类的属性和其他方法(Go 语言不支持隐藏的 this 指针,所有的东西都是显式声明)。

上述方法是一个只读方法,如果我们要在外部通过 Student 类暴露的方法设置 name 值,可以这么做:

func (s *Student) SetName(name string) {    s.name = name}

你可能已经注意到,这里的方法声明和前面 GetXXX 方法声明不太一样,Student 类型设置成了指针类型:

s *Student

这是因为 Go 语言面向对象编程不像 PHP、Java 那样支持隐式的 this 指针,所有的东西都是显式声明的,在 GetXXX 方法中,由于不需要对类的成员变量进行修改,所以不需要传入指针,而 SetXXX 方法需要在函数内部修改成员变量的值,并且作用到该函数作用域以外,所以需要传入指针类型(结构体是值类型,不是引用类型,所以需要显式传入指针)。

注:我们可以把接收者类型为指针的成员方法叫做指针方法,把接收者类型为非指针的成员方法叫做值方法。

接下来,我们可以在 main 函数中初始化 Student 类之后,通过 SetName 方法修改 name 值,然后再通过 GetName 将其打印出来:

student := NewStudent(1, "学院君", 100)student.SetName("学院君小号")fmt.Println("Name:", student.GetName())

打印结果是:

Name: 学院君小号

PHP、Java 支持默认调用类的 toString 方法以字符串格式打印类的实例,Go 语言也有类似的机制,只不过这个方法名是 String,以上面这个 Student 类型为例,我们为其编写 String 方法如下:

func (s Student) String() string {    return fmt.Sprintf("{id: %d, name: %s, male: %t, score: %f}",        s.id, s.name, s.male, s.score)}

然后我们可以在 main 方法中这样调用来打印类实例:

student := NewStudent(1, "学院君", 100)fmt.Println(student)

无需显式调用 String 方法,Go 语言会自动调用该方法来打印,结果如下:

{id: 1, name: 学院君, male: false, score: 100.000000}

一个数据类型关联的所有方法,共同组成了该类型的方法集合。同一个方法集合中的方法不能出现重名,并且,如果它们所属的是一个结构体类型,那么它们的名称与该类型中任何字段的名称也不能重复。

除了基于结构体定义的自定义类之外,Go 语言还支持为任何类型添加成员方法,包括基本类型,下一篇我们将演示如何给前面数据类型系列中介绍的基本类型和复合类型添加成员方法,实现类似 Java 的「装箱」(boxing)功能。

推荐阅读

  • 猜猜看go是不是面向对象语言?能不能面向对象编程?


喜欢本文的朋友,欢迎关注“Go语言中文网”:

77686349796f06856bb6836620229f09.png

Go语言中文网启用微信学习交流群,欢迎加微信:274768166

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值