go 面向对象的处理方式

2023-11-05

go语言特性

  • Golang语言没有C++、JAVA一样有面向对象(封装、继承、多态)相关的概念,但是面向对象只是一种编程思想,go借助于struct、interface这两个go的数据类型可以实现面向对象的处理,struct是一种包含了数据成员和方法的类型。
  • Golang里面有组合的概念,也就是一个struct 里面可以包含一个或者多个struct,struct可以近似理解为面向对象编程中的class,但是不能等同,有很多区别。如果一个struct实现了某个接口的所有方法,那么只要是包含这个struct的所有其他struct也都是实现了这个接口的所有方法。

封装

封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式

1、类: 在 Go 语言中可以使用结构体(Structs)对属性进行封装,结构体就像是类的一种简化形式。

例如,我们要定义一个矩形,每个矩形都有长和宽,我们可以这样进行封装:

type Rectangle struct {
    Length int
    Width int
}

2、类的方法:Go 语言中也有方法),Go 方法是作用在接收者(receiver)上的一个函数,接收者是某种类型的变量,但不能是接口类型。因此方法是一种特殊类型的函数。

定义方法的格式如下:

func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }

上文中我们已经定义了一个矩形 Rectangle,现在我们要定义一个方法 Area() 来计算它的面积:

package main
import (
    "fmt"
)
// 矩形结构体
type Rectangle struct {
    Length int
    Width  int
}

// 计算矩形面积
func (r *Rectangle) Area() int {
    return r.Length * r.Width
}

func main() {
    r := Rectangle{4, 2}
    // 调用 Area() 方法,计算面积
    fmt.Println(r.Area())
}
上面的代码片段输出结果为 8

3、访问权限:一个类的属性是公共的还是私有的,在c++、java编程语言中,我们常用 public 与 private 关键字来表达这样一种访问权限。在 Go 语言中没有 public、private、protected 这样的访问控制修饰符,它是通过字母大小写来控制可见性的。

   如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头,这表示它们能被其它包访问或调用(相当于 public);非大写开头就只能在包内使用(相当于 private)。

   如何访问未导出字段: 当遇到只能在包内使用的未导出字段时,我们又该如何访问呢?和其他面向对象语言一样,Go 语言也有实现 getter 和 setter 的方式:对于 setter 方法使用 Set大写前缀让外包调用给未导出成员赋值。对于 getter 方法使用大写前缀Get,并返回相关的未导出成员的值。例如我们现在有一个处于 person 包中的 Person 结构体:

package person

type Person struct {
    firstName string
    lastName  string
}
//我们可以看到,它的两个成员变量都是非大写字母开头,只能在包内使用,现在我们为其中的 firstName 来定义 setter 与 getter :

// 获取 firstName
func (p *Person) FirstName() string {
    return p.firstName
}

// 设置 firstName
func (p *Person) SetFirstName(newName string) {
    p.firstName = newName
}
//这样一来,我们就可以在 main 包里设置和获取 firstName 的值了:

-----

package main

import (
    "fmt"

    "./person"
)

func main() {
    p := new(person.Person)
    p.SetFirstName("firstName")
    fmt.Println(p.FirstName())
}

/* Output:
firstName
*/

继承

继承:使得子类具有父类的属性和方法或者重新定义、追加属性和方法等,继承在两个类之间建立的是is-a的关系。

在 Go 语言中一般使用在结构体中内嵌匿名类型的方法来实现继承。匿名类型:即这些类型没有显式的名字。匿名组合类型是相当于用其类型名称(去掉包名部分)作为成员变量的名字。go的继承可以把struct看做类,struct中可以包含其它的struct,继承内部struct的方法和变量,同时可以重写内部继承的struct的方法和变量。当外层结构体声明了一个函数与匿名内嵌成员所声明的函数同名时,再直接调用调用该函数,将会覆盖内嵌成员的同函数,也即是说,这实现了覆盖 override 效果。

引入匿名域(Person)实现了is-a关系,匿名域只给出了对象类型,而不给出类型的名字。通过匿名域,外层结构体对象可以直接调用内嵌成员所声明的方法,而无需带成员名或类型名(匿名成员本来就只有类型名,而无成员名),而这种调用方式就像是外层结构体对象在调用自己声明的方法一样。

例如:我们定义一个 Engine 接口类型,一个 Car 结构体,让 Car 结构体包含一个 Engine 类型的匿名字段:

type Engine interface {
    Start()
    Stop()
}

type Car struct {
    Engine // 包含 Engine 类型的匿名字段
}
//此时,匿名字段 Engine 上的方法「晋升」成为了外层类型 Car 的方法。我们可以构建出如下代码:

func (c *Car) GoToWorkIn() {
    // get in car
    c.Start()
    // drive to work
    c.Stop()
    // get out of car
}

虚基类

Golang可以interface + struct来实现虚基类的用法,若struct的成员是一个接口类型,若传入接口类型的成员实现了interface中定义的方法。若接口成员为匿名成员,则外层结构体可以直接调用接口中的方法。若想要某一结构体拥有某一接口不同的实现方法时,可以把接口类型作为结构体的一个类型成员。接口成员赋予不同的实现者时,结构体拥有不同的接口实现方法

type Clothe interface {
    SayColor()
}

type BlueClothe struct {
    Color string
}

func (b *BlueClothe) SayColor()  {
    log.Println("Blue")
}


type Stu struct {
    Clothe
    Name string
}

func main() {
    blue:=&BlueClothe{Color:"Blue"}
    var stu Stu
    stu.Clothe = blue //匿名类型名字就是类型名
    stu.Name="biningo"
    stu.SayColor()
}

这种特性在一些注册插件的功能代码中较为常见,因为传入结构体的接口类型成员的实现者不同,则结构体拥有不同逻辑的接口实现方法。

type IProxy interface {
	HandleFunc(url, req string) (interface{}, int, error)
}

type httpHandler struct {
	IProxy
}

组合

组合:每当某个类包含另一个类的对象作为其显式成员变量之一时,就会出现类组合。组合在两个类之间建立了(Has-a)的关系

go语言中,如果一个struct嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体字段或方法时,就必须带上结构体的名字。


多态

多态:不同对象中同种行为的不同实现方式

在面向对象中,多态的特征为:不同对象中同种行为的不同实现方式。在 Go 语言中可以使用接口interface实现这一特征。 可以把匿名域绑定到一个接口,也能绑定到多个接口。接口和匿名域一起使用,可以起到和多态同样的效果。

我们先定义一个正方形 Square 和一个长方形 Rectangle:

// 正方形
type Square struct {
    side float32
}

// 长方形
type Rectangle struct {
    length, width float32
}

然后,我们希望可以计算出这两个几何图形的面积。但由于他们的面积计算方式不同,我们需要定义两个不同的 Area() 方法。于是,我们可以定义一个包含 Area() 方法的接口 Shaper,让 Square 和 Rectangle 都实现这个接口里的 Area():

// 接口 Shaper
type Shaper interface {
    Area() float32
}

// 计算正方形的面积
func (sq *Square) Area() float32 {
    return sq.side * sq.side
}

// 计算长方形的面积
func (r *Rectangle) Area() float32 {
    return r.length * r.width
}
我们可以在 main() 函数中这样调用 Area()func main() {
    r := &Rectangle{10, 2}
    q := &Square{10}

    // 创建一个 Shaper 类型的数组
    shapes := []Shaper{r, q}
    // 迭代数组上的每一个元素并调用 Area() 方法
    for n, _ := range shapes {
        fmt.Println("图形数据: ", shapes[n])
        fmt.Println("它的面积是: ", shapes[n].Area())
    }
}

/*Output:
图形数据:  &{10 2}
它的面积是:  20
图形数据:  &{10}
它的面积是:  100
*/

由以上代码输出结果可知:不同对象调用 Area() 方法产生了不同的结果,展现了多态的特征。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go 面向对象的处理方式 的相关文章

  • Golang GAE - 小胡子结构中的 intID

    这是一个Example https www dropbox com sh ur2ws1jnik6euef PjVJSwDTUc Blog Golang zip该应用程序的 关键代码在 golang code handler handler
  • 解组转义 XML

    在 Go 中 我将如何解码此 XML 响应 我尝试过建立一个自定义UnMarshal方法在我的Answerstruct 但我运气不太好
  • 打印到 stdout 会导致阻塞的 goroutine 运行吗?

    作为一个愚蠢的基本线程练习 我一直在尝试实现理发师睡觉的问题 http en wikipedia org wiki Sleeping barber problem在戈兰 对于通道来说 这应该很容易 但我遇到了一个 heisenbug 也就是
  • 为什么我不能将左大括号放在下一行?

    当我尝试编译以下代码时遇到奇怪的错误 package main import fmt fmt func main var arr 3 int for i 0 i lt 3 i fmt Printf d arr i 错误如下 unexpect
  • 正确的文件扩展名或缩写是什么。 golang 的文本/模板?

    我正在考虑为其创建语法荧光笔 但我不知道这种特定类型模板的常规缩写 In 例子之一 http golang org pkg text template example Template helpers从文本 模板 godoc 中 它们引用
  • 如何使信号量超时

    Go 中的信号量是通过通道来实现的 一个例子是这样的 https sites google com site gopatterns concurrency semaphores https sites google com site gop
  • 如何在golang中解析JSON而不需要解组两次

    我有一个 Web 套接字连接 它在 JSON 对象中发送不同类型的消息 并且我想将内容解组到一些已知的结构中 为此 我认为我应该执行以下操作 步骤 1 将 JSON 解组为通用映射 字符串 接口 步骤 2 找到我要找的钥匙 步骤 3 尝试将
  • 直接从一个通道发送到另一个通道

    当从一个通道直接发送到另一个通道时 我偶然发现了令人惊讶的行为 package main import fmt func main my chan make chan string chan of chans make chan chan
  • 如何仅在测试时允许一个包访问另一个包的未导出数据?

    In Go 编程语言 第 11 2 4 节 有一个外部测试访问的示例fmt isSpace 通过声明IsSpace in fmt s export test go文件 这似乎是完美的解决方案 所以这就是我所做的 a a go package
  • select 语句是否保证通道选择的顺序?

    继从这个答案 https stackoverflow com a 25795236 274460 如果一个 goroutine 在两个通道上进行选择 是否保证通道的选择顺序与其发送的顺序相同 我对发送者是单线程的情况特别感兴趣 例如 是否保
  • 如何为所有 API 端点全局设置 http.ResponseWriter Content-Type 标头?

    我是 Go 新手 现在正在用它构建一个简单的 API package main import encoding json fmt github com gorilla mux github com gorilla handlers log
  • 在 Go to 函数中通过引用和值传递

    我对 Go 中通过引用和值传递有点困惑 我已经看到过对类型前面的 的解释 在类型名称前面 表示声明的变量将存储该类型的另一个变量的地址 而不是该类型的值 类型 这对我来说毫无意义 在Java中 如果我将数据库实例传递给函数 我会这样做 da
  • 在 Golang 中运行外部 python,捕获连续的 exec.Command Stdout

    所以我的 go 脚本将像这样调用外部 python cmd exec Command python game py cmd Stdout os Stdout cmd Stderr os Stderr go func err cmd Run
  • 什么时候返回结构体指针是个好主意?

    我正在学习 Go 我对何时使用指针有点困惑 具体来说 当返回一个struct从函数中 什么时候适合返回结构体实例本身 什么时候适合返回指向结构体的指针 示例代码 type Car struct make string model strin
  • 使用 mgo 驱动程序进行 mongo 聚合查询

    我在 mongodb 中有以下查询 db devices aggregate match userId v73TuQqZykbxFXsWo state true project userId 1 categorySlug 1 weight
  • 指针上定义的方法仍然可以用值调用

    Effective Go 文档说明如下 关于接收者的指针与值的规则是 可以在指针和值上调用值方法 但只能在指针上调用指针方法 http tip golang org doc effective go html pointers vs val
  • 如何读取 UDP 连接直至超时?

    我需要读取 UDP 流量 直到超时 我可以通过在 UDPConn 上调用 SetDeadline 并循环直到出现 I O 超时错误来做到这一点 但这看起来很黑客 基于错误条件的流量控制 下面的代码片段看起来更正确 但并没有终止 在生产中 这
  • 如何通过在切片上查找来从切片复制到数组

    我正在编写一个库来处理二进制格式 我有一个带有数组变量的结构 我想保留它以用于文档目的 我还需要从输入字节片中查找和判断 一些伪代码 type foo struct boo 5 byte coo 3 byte func main input
  • 所有可能的 GOOS 价值?

    如果我做对了 GOOS在编译源代码时确定 为了更好地支持多个操作系统 我感兴趣的是GOOS可能 当然 Go 是开源的 所以它可能有无限的可能性 所以我真正想要的是一个 通用列表 已知值为 windows linux darwin or fr
  • golang中如何将相对路径解析为绝对路径?

    节点中是否有类似 path resolve 的API 或者有什么东西可以做同样的事情 例如 nodejs代码 path resolve sample sh 应该得到 home currentuser sample sh 解决 表示用户主目录

随机推荐

  • 下载好看的壁纸四个网站就够了,尤其第二个,高清免费壁纸随你挑

    壁纸作为手机电脑的第一印象 我想一张好看的壁纸可以让你的心情变得十分愉悦 每个人喜欢的壁纸类型也是不同的 有些人喜欢科技 动漫 有些人却喜欢唯美 自然 但是好看的壁纸随处都有 但未必时自己想要的哪一款 所以今天我就来给大家推荐一些可以获得大
  • 【SpringBoot】Idea中web项目上传文件相对路径问题

    项目场景 springboot开发javaweb项目 在文件上传接口中 使用transferTo方法保存文件 当采用相对路径时保存会报错 问题描述 相对路径会报一个这样的错误 java io IOException java io File
  • 怎样系统的学习 AI 绘画?模型代码案例

    怎样系统的学习 AI 绘画 学习 AI 绘画需要从以下几个方面进行系统的学习 数学基础 学习 AI 绘画需要具备一定的数学基础 包括线性代数 概率论 微积分等 这些数学知识是深度学习模型的基础 有助于理解模型的数学原理和算法细节 编程基础
  • 抽签助手

    抽签助手实现 学习记录 今天突发奇想想要尝试一波抽签助手 具体代码如下 include
  • tomcat9调优2:Tomcat线程模型分析及其性能调优

    文章目录 Tomcat线程模型分析及其性能调优 Tomcat的IO模型 tomcat设计精髓点 Tomcat调优 Tomcat线程模型分析及其性能调优 Tomcat的IO模型 Tomcat 支持的多种 I O 模型和应用层协议 Tomcat
  • 基于计算机视觉实现自动报靶系统

    基于计算机视觉实现自动报靶系统 自动报靶系统是一种通过计算机视觉技术实现的靶标自动识别和跟踪的系统 该系统可以应用于一些需要高精度打靶的场合 如射击比赛 训练等 本文将介绍如何使用MATLAB实现一个基于计算机视觉的自动报靶系统 准备工作
  • LoadRunner录制图片验证码

    LoadRunner录制图片验证码 LoadRunner自身是无法捕获到图片验证码的 但是我们可以帮助LoadRunner来实现验证码的捕获 1 图片验证码 图片验证码的产生来自服务器端 由服务器生成随机数 然后写入到图片中 虽然LR可以录
  • 恢复图像-进行反卷积和非盲去卷积恢复原始图像

    这段 MATLAB 代码实现了对添加噪声的图像进行反卷积和非盲去卷积的处理 以恢复原始图像 读取失真图像 这里是标准的 img imread image jpg 转换图像的类型为double img im2double img 计算图像的大
  • 6、SpringBoot - 日志配置

    01 项目日志格式 Spring Boot 的默认日志输出类似于以下示例 2021 12 14 22 40 14 159 INFO 20132 main com kuangstudy SpringbootApplication Starte
  • Transfomer编码器中自注意力机制、前馈网络层、叠加和归一组件等讲解(图文解释)

    Transformer中的编码器不止一个 而是由一组N个编码器串联而成 一个编码的输出作为下一个编码器的输入 如下图所示 每一个编码器都从下方接收数据 再输出给上方 以此类推 原句中的特征会由最后一个编码器输出 编码器模块的主要功能就是提取
  • CCF CSP 认证 201612-2 工资计算 C语言

    include
  • 用抽象分层的方法分析Android的渲染和显示系统

    Hello World
  • Hinton关于RBM的代码注解之(二)backpropclassify.m

    源代码 http www cs toronto edu hinton MatlabForSciencePaper html 这个是关于RBM的微调步骤的代码 代价函数是交叉熵 Version 1 000 Code provided by R
  • Springboot-aop(一)

    引入依赖
  • EfficientNet与EfficientDet论文解读

    这两项工作均来自Google Brain的大佬 EfficientDet可以看做EfficientNet的工作拓展 目前EfficientNet的代码已经开源 EfficientDet已经被复现 这两项工作的纸面效果看起来特别优秀 与其他工
  • Python3中PyMongo使用举例

    MongoDB是一个基于分布式文件存储的开源数据库 由C 语言编写 与平台无关 旨在为WEB应用提供可扩展的高性能数据存储解决方案 MongoDB是一个介于关系数据库和非关系数据库之间的产品 是非关系数据库中功能最丰富 最像关系数据库的 它
  • Bart模型应用实例及解析(二)————基于泰坦尼克号数据集的分类模型

    Bart模型应用实例及解析 二 基于泰坦尼克号数据集的分类模型 前言 一 数据集 1 数据集的获取 2 数据集变量名及意义 3 数据集处理 二 完整代码 三 代码运行结果及解析 1 数据描述性分析 2 建立Bart模型以及分析 3 各模型效
  • __HAL_TIM_SET_CAPTUREPOLARITY的巨坑

    本人在写输入捕获实验的时候使用HAL库中的函数 HAL TIM SET CAPTUREPOLARITY试图切换捕获极性 keil一直报错error expected error expected expression 原以为 HAL TIM
  • 51单片机---流水灯独立按键之控制速度

    文章目录 前言 一 问题 二 代码 前言 对于某些实验室的初级考核内容 以下是代码实例 一 问题 流水灯独立按键之控制速度 用按键控制led的流水灯的流速 要求 LED从左开始 然后左右来回流水 定义三个独立按键 按下按键 改变流速 要求实
  • go 面向对象的处理方式

    go语言特性 Golang语言没有C JAVA一样有面向对象 封装 继承 多态 相关的概念 但是面向对象只是一种编程思想 go借助于struct interface这两个go的数据类型可以实现面向对象的处理 struct是一种包含了数据成员