当前位置: 首页 > news >正文

Go语言程序设计-第6章--方法

Go语言程序设计-第6章–方法

对象就是简单的一个值或者变量,并且拥有其方法,而方法是某种特定类型的函数。

6.1 方法的声明

方法的声明和普通函数的声明类似,只是在函数名字前面多了一个参数。这个参数把这个方法绑定到这个参数对应的类型上。

package geometryimport "math"type Point struct { X, Y float64 }// 普通函数
func Distince(p, q Point) float64 {return math.Hypot(q.X - p.X, q.Y - p.Y)
}// Point 类型的方法
func (p Point)Distince(q Point) float64 {return math.Hypot(q.X - p.X, q.Y - p.Y)
}

附加的参数 p 称为方法的接收者。接收者不使用特殊名(比如 this 或者 self)。

表达式 p.Distance 称为选择子(selector), 因为它为接受者 p 选择合适的 Distince 方法。

6.2 指针接收者的方法

由于主调函数会复制每个实参变量,如果函数需要更新一个变量,或者如果一个实参太大而我们希望避免复制整个实参。我们必须使用指针来传递变量的地址。

func (p *Point) ScaleBy(factor float64) {p.X *= factor;p.Y *= factor;
}

命令类型(Point)和指向他们的指针(* Point)是唯一可以出现在接收者声明处的类型。
在真实的程序中,如果 Point 的任何一个方法使用指针接收者,那么所有的 Point 方法都应该使用指针接收者。

如果方法要求一个 *Point 接收者,我们可以使用简写:

p.ScaleBy(2)

编译器会对变量进行 &p 的隐私转换。只有变量才允许这么做,包括结构体字段,像 p.X 和数组或者 slice 元素,比如 perim[0]。

Point(1,2).ScaleBy(2) // 编译错误,不能获得 Poing 类型字面量的地址

如果实参接收者是 * Point 类型,以 Point.Distance 方式调用Point类型的方法是合法的。编译器自动插入一个隐式的 * 操作符。

p := Point{1, 2}
pptr := &ppptr.Distance(q)
(*pptr).Distance(q)
  • nil 是一个合法的接收者
// IntList 是整形链表
// * IntList 的类型 nil 代表空列表
type IntList struct {Value intTail *IntList
}// Sum 返回表元素的总和
func (list *IntList) Sum() int {if list == nil {return 0}return list.Value + list.Tail.Sum()
}

6.3 通过结构体内嵌组成类型

import "image/color"type Point struct{X, Y float 64}type ColoredPoint struct {PointColor color.RGBA
}
var cp ColoredPoint
cp.X = 1

能够通过类型为 ColoredPoint 的接收者调用内嵌类型 Point 的方法。

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}
p.ScaleBy(2)
p.Distnace(q.Point)

Point 的方法都被纳入到 ColorPoint 类型中。

在 go 语言,Point 类型不是 ColoredPoint 类型的基类。

ColoredPoint 包含一个Point,并且它有两个另外的方法 Distance 和 ScaleBy 来自 Point。如果考虑具体实现,实际上,内嵌的字段会告诉编译器生成额外的包装方法来调用 Point 声明的方法,这相当于以下代码。

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

匿名字段类型可以是指向命名类型的指针,这个时候,字段和方法间接地来自所指向的对象。

结构体类型可以拥有多个匿名字段。声明 ColoredPoint:

type ColoredPoint struct {Pointcolor.RGBA
}

那么这个类的值可以拥有 Point 所有的方法和 RGBA 所有的方法,以及任何其他直接在 ColoredPoint 类型中声明的方法。当编译器处理选择子(比如 p.ScaleBy)的时候,首先,先查找直接声明的方法 ScaleBy, 之后在从来自 ColoredPoint 的内嵌字段的方法进行查找,这里的方法经过一次提升;最后从 Point 和 RGBA 中内嵌的方法中进行查找,这里的方法经过2次提升。
如果同一个级别有两个同名的函数提升,则编译器会报错。如Point 和 color.RGBA 都有 Scaleby 函数。

6.4 方法变量与表达式

p.Dsitance 可以赋予一个方法变量,他是一个函数,把方法(Point.Distance)绑定到一个接收者 p 上。函数只需要提供实参而不需要提供接收者就能够调用。

p := Point{1, 2}
q := Point{4, 6}
distanceFromP := p.Distance // 方法变量
fmt.Println(distanceFromP(q))

与方法变量相关的是方法表达式。在方法表达式写成 T.f 或者(*T).f,其中 T 是类型,是一种函数变量,把原来方法的接收者替换成函数的第一个形参,因此它可以像平常的安徽省南一样调用。

package mainimport ("fmt""math"
)type Point struct{ X, Y float64 }func (p Point) Distance(q Point) float64 {return math.Hypot(q.X-p.X, q.Y-p.Y)
}func (p *Point) ScaleBy(factor float64) {p.X *= factorp.Y *= factor
}func main() {p := Point{1, 2}q := Point{4, 6}distance := Point.Distance // 方法表达式fmt.Println(distance(p, q))scale := (*Point).ScaleByscale(&p, 2)fmt.Println(p)            //{2, 4}fmt.Printf("%T\n", scale) // func(*Point, float64)
}

6.5 示例:位向量

6.6 封装

type IntSet struct {words []uint64
}

可以定义为

type IntSet []uint64

使用时把 s.words 换成 *s。
尽管这个版本的 IntSet 和之前的基本相同,但是它允许其他包内的方法读取和改变这个 slice。换句话说,表达式 *s 可以在其他包内使用,s.words 只能在定义 IntSet 的包内使用。

另一个结论是Go语言封装的单元是包而不是类型。无论是函数内的代码还是方法内的代码,结构体类型内的字段对于同一个包中的所有代码都是可见的。

封装提供了三个优点。
第一,因为使用方不能直接修改对象的变量,所以不需要更多的语句来检查变量的值。
第二,隐藏实现细节可以防止使用方依赖的属性发生改变,使得设计者可以更加灵活地改变 API 的实现而不破坏兼容性。
第三,防止使用者肆意地改变对象内部的变量。

相关文章:

Go语言程序设计-第6章--方法

Go语言程序设计-第6章–方法 对象就是简单的一个值或者变量,并且拥有其方法,而方法是某种特定类型的函数。 6.1 方法的声明 方法的声明和普通函数的声明类似,只是在函数名字前面多了一个参数。这个参数把这个方法绑定到这个参数对应的类型…...

AI按理说应该最擅长理工,为啥先冲击文艺行业?

介绍 本人数据AI工程师,我的观点对全行业都有冲击,当AI大模型持续进化之时,没有一家公司能独善其身。 本文从产业架构上、论文体量、基础Pass能力、通用大模型、AI开源社区、业务属性大模型、内容消费工具、创作工具赛道、企业服务这些板块…...

蓝牙物联网移动硬件数据传输系统解决方案

随着传感器技术、网络技术和数据传输技术的不断发展,人们对智能设备的需求日渐增强,利用传感器技术可以对周围环境进行准确和全面的感知,获取到实时信息,从而在网络中进行传输和共享,再通过服务器对各种数据进行保存、分析和挖掘等…...

Linux下Web服务器工作模型及Nginx工作原理详解

文章目录 1. 工作模型概述1.1 阻塞、非阻塞、同步、异步浅析1.2 Web服务器处理并发请求的方式 2. Linux下的I/O模型2.1 常用I/O模型2.2 对比以上模型 3. Nginx工作原理3.1 Nginx基本架构3.2 Nginx代码结构3.3 Nginx工作流程3.4 Nginx缓存机制3.5 Nginx缓存工具:Memc…...

AJAX: 整理2:学习原生的AJAX,这边借助express框架

1. npm install express 终端直接安装 2. 测试案例:Hello World! 新建一个express.js的文件,写入下方的内容 // 1. 引入express const express require(express)// 2. 创建服务器 const app express()// 3.创建路由规则 // request 是对请…...

二、计算机软件及其使用-文字处理软件 Word 2016

Word 2016 的功能;Word 2016 的启动方法和工作窗口 Word 2016 的功能 编辑功能、排版功能、表格处理功能、图形与公式处理功能、文档管理功能 Word 2016 的启动方法 桌面有就单击、任务栏有就单击、开始菜单中单击 Word 2016 的工作窗口 标题栏、功能区、工作区、状…...

Linux LVM逻辑卷

一、LVM的定义 LVM 是 Logical Volume Manager 的简称,译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。LVM 适合于管理大存储设备,并允许用户动态调整文件系统的大小。此外,LVM 的快照功能可以帮助我们快速备份数据。LVM 为…...

Hive生产调优介绍

1.Fetch抓取 Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM employees;在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。 在hive-default.xml…...

如何理解鼠标点击事件在程序中的处理

在计算机用户界面中,鼠标点击是一个常见的交互动作。那么,当你按下鼠标时,程序是如何知道这个点击是否针对它自己的按钮的呢?本文将探讨鼠标点击事件在操作系统和应用程序之间的传递过程。 鼠标点击事件的捕获 当你按下鼠标按钮…...

基于JWT的用户token验证

1. 基于session的用户验证 2. 基于token的用户身份验证 3. jwt jwt代码实现方式 1. 导包 <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.18.2</version> </dependency> 2. 在登录…...

通过 conda 安装 的 detectron2

从 detectron2官网 发现预编译的版本最高支持 pytorch1.10、cuda11.3。&#xff08;2023-12-26&#xff09; 1、安装 conda 环境。 conda create --name detectron2 python3.8 2、安装 pytorch1.10 和 cuda11.3。 pip3 install torch1.10.0cu113 torchvision0.11.1cu113 torc…...

嵌入式开发——SPI OLED屏幕案例

学习目标 掌握移植方法掌握调试方式学习内容 需求 官方测试示例 选择对应的平台 测试示例中,找到芯片对应平台,我们选择的是STM32F407 修改例程 已知错误修改:...

ibm上电时序(视频内容)

...

如何在Vue.js中使用$emit进行组件通信

Vue.js是一个渐进式JavaScript框架&#xff0c;它以其简洁的数据绑定和组件系统而闻名。在构建具有多个组件层次的Vue应用时&#xff0c;组件间的通信成为一个关键的话题。Vue提供了一种名为$emit的方法&#xff0c;允许子组件向父组件发送消息。本文将详细介绍如何在Vue中使用…...

SPSS相关统计学知识精要回顾-大家都来做做

很多学生问我&#xff0c;学SPSS如果想深入学&#xff0c;那么统计学原理应该掌握到什么样的水准&#xff0c;我想说的是&#xff0c;如果真的想融会贯通&#xff0c;而不是短暂过关&#xff0c;那么应该具备一定的统计学基础&#xff0c;但是统计学知识也不是面面俱到都要去学…...

React Native 从类组件到函数组件

1. 发展趋势 React Native社区中的趋势是朝向使用函数组件&#xff08;Functional Components&#xff09;和Hooks的方向发展&#xff0c;而不是使用类组件&#xff08;Class Components&#xff09;。 React Native自推出Hooks API以来&#xff0c;函数组件和Hooks的使用变得…...

Redis 快速搭建与使用

文章目录 1. Redis 特性1.1 多种数据类型支持1.2 功能完善1.3 高性能1.4 广泛的编程语言支持1.5 使用简单1.6 活跃性高/版本迭代快1.7 I/O 多路复用模型 2. Redis发展历程3. Redis 安装3.1 源码安装3.1.1 下载源码包3.1.2 解压安装包3.1.3 切换到 Redis 目录3.1.4 编译安装 3.2…...

SpringBoot集成etcd,实现实时监听,实现配置中心

etcd 是一个分布式键值对存储&#xff0c;设计用来可靠而快速的保存关键数据并提供访问。通过分布式锁&#xff0c;leader选举和写屏障(write barriers)来实现可靠的分布式协作。etcd集群是为高可用&#xff0c;持久性数据存储和检索而准备。 以下代码实现的主要业务是&#xf…...

JavaScript元素根据父级元素宽高缩放

/*** 等比缩放* param wrap 外部容器* param container 待缩放的容器* returns {{width: number, height: number}}* 返回值&#xff1a;width:宽度, height:高度*/aspectRatio(wrap: any, container: any) {// w h / ratio, h w * ratioconst wrapW wrap.width;const wrapH…...

易趋产品升级(EasyTrack 11_V1.3) | 集成飞书、WPS、个性化设置,增强团队协作和用户体验

企业在项目管理过程中&#xff0c;经常会遇到项目信息同步不及时、沟通障碍以及管理软件使用不便捷等难题&#xff0c;导致团队协作效率低下。这种情况下&#xff0c;如果使用了多个办公软件&#xff08;如&#xff1a;钉钉、企业微信、项目管理软件等&#xff09;&#xff0c;…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...