go语言方法之通过嵌入结构体来扩展类型

        我们先来看看这个类型:

import "image/color"type Point struct{ X, Y float64 }type ColoredPoint struct {PointColor color.RGBA
}

        我们完全可以将ColoredPoint定义为一个有三个字段的struct,但是我们却将Point这个类型嵌 入到ColoredPoint来提供X和Y这两个字段。像我们之前中看到的那样,内嵌可以使我们在 定义ColoredPoint时得到一种句法上的简写形式,并使其包含Point类型所具有的一切字段, 然后再定义一些自己的。如果我们想要的话,我们可以直接认为通过嵌入的字段就是 ColoredPoint自身的字段,而完全不需要在调用时指出Point,比如下面这样。

var cp ColoredPoint
cp.X = 1
fmt.Println(cp.Point.X) // "1"
cp.Point.Y = 2
fmt.Println(cp.Y) // "2"

        对于Point中的方法我们也有类似的用法,我们可以把ColoredPoint类型当作接收器来调用 Point里的方法,即使ColoredPoint里没有声明这些方法:

red := color.RGBA{255, 0, 0, 255}
blue := color.RGBA{0, 0, 255, 255}
var p = ColoredPoint{Point{1, 1}, red}
var q = ColoredPoint{Point{5, 4}, blue}
fmt.Println(p.Distance(q.Point)) // "5"
p.ScaleBy(2)
q.ScaleBy(2)
fmt.Println(p.Distance(q.Point)) // "10"

        Point类的方法也被引入了ColoredPoint。用这种方式,内嵌可以使我们定义字段特别多的复 杂类型,我们可以将字段先按小类型分组,然后定义小类型的方法,之后再把它们组合起 来。

        如果对基于类来实现面向对象的语言比较熟悉的话,可能会倾向于将Point看作一个基 类,而ColoredPoint看作其子类或者继承类,或者将ColoredPoint看作"is a" Point类型。但这 是错误的理解。请注意上面例子中对Distance方法的调用。Distance有一个参数是Point类 型,但q并不是一个Point类,所以尽管q有着Point这个内嵌类型,我们也必须要显式地选择 它。尝试直接传q的话你会看到下面这样的错误:

p.Distance(q) // compile error: cannot use q (ColoredPoint) as Point

        一个ColoredPoint并不是一个Point,但他"has a"Point,并且它有从Point类里引入的Distance 和ScaleBy方法。如果你喜欢从实现的角度来考虑问题,内嵌字段会指导编译器去生成额外的 包装方法来委托已经声明好的方法,和下面的形式是等价的:

func (p ColoredPoint) Distance(q Point) float64 {return p.Point.Distance(q)
}func (p *ColoredPoint) ScaleBy(factor float64) {p.Point.ScaleBy(factor)
}

        当Point.Distance被第一个包装方法调用时,它的接收器值是p.Point,而不是p,当然了,在 Point类的方法里,你是访问不到ColoredPoint的任何字段的。

         在类型中内嵌的匿名字段也可能是一个命名类型的指针,这种情况下字段和方法会被间接地 引入到当前的类型中(译注:访问需要通过该指针指向的对象去取)。添加这一层间接关系让我 们可以共享通用的结构并动态地改变对象之间的关系。下面这个ColoredPoint的声明内嵌了一 个*Point的指针。

type ColoredPoint struct {*PointColor color.RGBA
}
p := ColoredPoint{&Point{1, 1}, red}
q := ColoredPoint{&Point{5, 4}, blue}
fmt.Println(p.Distance(*q.Point)) // "5"
q.Point = p.Point // p and q now share the same Point
p.ScaleBy(2)
fmt.Println(*p.Point, *q.Point) // "{2 2} {2 2}"

        一个struct类型也可能会有多个匿名字段。我们将ColoredPoint定义为下面这样:

type ColoredPoint struct {Pointcolor.RGBA
}

        然后这种类型的值便会拥有Point和RGBA类型的所有方法,以及直接定义在ColoredPoint中的 方法。当编译器解析一个选择器到方法时,比如p.ScaleBy,它会首先去找直接定义在这个类 型里的ScaleBy方法,然后找被ColoredPoint的内嵌字段们引入的方法,然后去找Point和 RGBA的内嵌字段引入的方法,然后一直递归向下找。如果选择器有二义性的话编译器会报错,比如你在同一级里有两个同名的方法。

        方法只能在命名类型(像Point)或者指向类型的指针上定义,但是多亏了内嵌,有些时候我们 给匿名struct类型来定义方法也有了手段。

        下面是一个小trick。这个例子展示了简单的cache,其使用两个包级别的变量来实现,一个 mutex互斥量和它所操作的cache:

var (mu sync.Mutex // guards mappingmapping = make(map[string]string)
)
func Lookup(key string) string {mu.Lock()v := mapping[key]mu.Unlock()return v
}

        下面这个版本在功能上是一致的,但将两个包级吧的变量放在了cache这个struct一组内:

var cache = struct {sync.Mutexmapping map[string]string
}{mapping: make(map[string]string),
}
func Lookup(key string) string {cache.Lock()v := cache.mapping[key]cache.Unlock()return v
}

        我们给新的变量起了一个更具表达性的名字:cache。因为sync.Mutex字段也被嵌入到了这个 struct里,其Lock和Unlock方法也就都被引入到了这个匿名结构中了,这让我们能够以一个简 单明了的语法来对其进行加锁解锁操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/19377.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图片处理软件有哪些?这三款软件好用

图片处理软件有哪些?在当今这个数字化时代,图片处理软件成为了我们日常生活和工作中不可或缺的工具。无论是为了修饰个人照片,还是为了设计专业海报,这些软件都能帮助我们轻松实现创意和美化。那么,究竟有哪些热门的图…

【因果推断python】1_因果关系初步1

目录 为什么需要关心因果关系? 回答不同类型的问题 当关联确实是因果时 为什么需要关心因果关系? 首先,您可能想知道:它对我有什么好处?下面的文字就将围绕“它”展开: 回答不同类型的问题 机器学习目…

数据结构【队列】

队列的的概念 队列是一种特殊的线性表,特殊之处在于它只允许在表的头部进行删除操作,而在表的尾部进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中…

Nginx R31 doc-10-NGINX Reverse Proxy 反向代理

配置 NGINX 作为反向代理 配置 NGINX 作为反向代理用于 HTTP 和其他协议,支持修改请求头和对响应进行细粒度的缓冲。 本文介绍了代理服务器的基本配置。您将学习如何将请求从 NGINX 转发到不同协议的代理服务器上,修改发送到代理服务器的客户端请求头&…

全球首个多语种手语视频生成模型诞生:SignLLM

近日,一项名为 SignLLM 的新型 AI 技术取得了突破性进展,或将彻底改变听障人士的沟通方式。作为全球首个多语种手语生成模型,SignLLM 能够将输入的文本或语音指令,实时转化为对应的手语手势视频,为打破语言障碍、促进信…

TiDB-从0到1-分布式事务

TiDB从0到1系列 TiDB-从0到1-体系结构TiDB-从0到1-分布式存储TiDB-从0到1-分布式事务TiDB-从0到1-MVCC 一、事务定义 这属于老生常谈了,无论不管是传统事务还是分布式事务都离不开ACID A:原子性C:一致性I:隔离性D:…

怎么查看 iOS ipa包 mobileprovision 改动

查看 iOS .ipa 包中的 .mobileprovision 文件(即配置文件或描述文件)的改动,可以通过以下步骤进行: 重命名 .ipa 文件:将 .ipa 文件扩展名改为 .zip。例如,如果文件名为 MyApp.ipa,则重命名为 M…

A 股涨停板实时数据 API 数据接口

A 股涨停板实时数据 API 数据接口 股票 / A股 / 涨停数据,所有A股涨停板实时数据,A 股涨停数据 / 实时数据。 1. 产品功能 支持所有 A 股涨停板实时数据查询;包含 A 股实时交易多项指标数据;毫秒级查询性能;全接口支…

Linux系统编程(五)多线程创建与退出

目录 一、基本知识点二、线程的编译三、 线程相关函数1. 线程的创建(1)整型的传入与接收(2)浮点数的传入与接收(3)字符串的传入与接收(4)结构体的传入与接收 2. 线程的退出3. 线程的…

机器学习笔记——线性回归、梯度下降

线性回归 什么是线性回归就不说了,直接说线性回归的目标就是首先需要一个损失函数,使得损失函数最小化来训练得出的模型,最常用的损失函数是均方误差 例子 如果要预测房屋平均售价之前需要对数据标准化,用到StandarScalar这个类&…

FastGPT私有化部署+OneAPI配置大模型

介绍 FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景! 官网地址 https://doc.fastai.site/docs/intro/ 部署 FastGPT提供…

frp转发服务

将内网服务转发到外网,我准备了一台阿里云ubuntu22.04服务器,两台内网ubuntu22.04服务器 下载frpc和frps以及配置文件 链接: https://pan.baidu.com/s/1auvcWWnyfpYPYatYhHFYag?pwdqkgh 提取码: qkgh 复制这段内容后打开百度网盘手机App,操作…

如何实现数据的正确拆分?

我们知道在传统的单块架构中,一个系统中只存在一个独立的服务和数据库实例。 上图中的系统架构实现起来比较简单,但是扩展性和伸缩性都比较差。因此,越来越多的系统开始采用了微服务架构。在微服务架构中,一个系统被拆分成多个服务…

6种经典的网页布局设计,你最喜欢哪个?

信息时代,我们每天都会浏览很多网页,但你有没有想过,让你停留在一个新网页的关键因素有哪些?毫无疑问,网页布局一定是关键因素之一。一个优秀的网页布局不仅可以让网站看起来更美观、更专业,还能够抓住用户…

R 语言入门学习笔记:软件安装踩坑记录——删除所有包以及彻底解决库包被安装到 C 盘用户目录下的问题,以及一些其他需要注意的点

文章目录 R 语言入门学习笔记:软件安装踩坑记录——删除所有包以及彻底解决库包被安装到 C 盘用户目录下的问题,以及一些其他需要注意的点软件版本及环境遇到的问题描述问题的分析和探究最终的解决方案折中方案根治方案 其他在安装过程中需要注意的问题 …

高效记录收支明细,预设类别账户,智能统计财务脉络,轻松掌握个人财务!

收支明细管理是每位个人或企业都必须面对的财务任务,财务管理已经成为我们生活中不可或缺的一部分。如何高效记录收支明细,预设类别账户,智能统计财务脉络,轻松掌握个人财务?晨曦记账本为您提供了完美的解决方案&#…

Java 面向对象编程(OOP)

面向对象编程(Object-Oriented Programming,OOP)是Java编程语言的核心思想之一。通过OOP,Java提供了一种结构化的编程方式,使代码更易于维护和扩展。 一、类和对象 1. 类的定义 类是对象的蓝图或模板,定…

File name ‘xxxx‘ differs from already included file name ‘xxxx‘ only in casing.

一、报错信息 VSCode报错如下: File name ‘d:/object/oral-data-management/src/components/VisitLogPopup/Info.vue’ differs from already included file name ‘d:/object/oral-data-management/src/components/VisitLogPopup/INfo.vue’ only in casing. The…

【PostgreSQL17新特性之-事务级别超时参数transaction_timeout】

PostgreSQL数据库里有多个和会话相关的参数,PostgreSQL17-beta1版本新增了一个transaction_timeout参数,来限制事务的持续时间。 当前的一些和会话相关的超时参数如下 -----------------------------------------------------------------------------…

备忘录模式具体的例子(含代码)

学习目标: 了解备忘录模式 学习内容: 备忘录模式在现实生活中的一个具体例子是文字处理软件(如Microsoft Word)中的“撤销”功能。这个功能允许用户在编辑文档时撤销之前的操作,并恢复到之前的状态。让我们更详细地看…