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 的实现而不破坏兼容性。
第三,防止使用者肆意地改变对象内部的变量。

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

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

相关文章

【影像组学入门百问】#58---#62

#58-使用PyRadiomics能提取出多少影像组学特征? 当前支持以下特征类别: 第一阶段统计量 基于形状的(3D) 基于形状的(2D) 灰度共生矩阵(GLCM) 灰度共生长度矩阵(GLRLM&a…

springboot接口文档

Swagger 在Spring Boot中生成和维护接口文档的一个常用方法是使用Swagger。Swagger是一个开源软件框架,它帮助开发者设计、构建、记录和使用RESTful Web服务。下面是在Spring Boot项目中使用Swagger来创建接口文档的详细步骤:1. 添加Swagger依赖 在你的Spring Boot项目的pom…

Go语言中的包管理工具之Go Path的使用

GoLang 中常用的包管理的方式 1 )概述 常用的有三种 Go PathGo VendorGo Modules 2 )发展历程 早期go的包管理存在很大缺陷,甚至可以说没有官方统一的包管理工具 一方面官方在努力发布一些实验性的包管理工具。同时也出现了很多社区开发…

使用uni-app editor富文本组件设置富文本内容及解决@Ready先于onload执行,无法获取后端接口数据的问题

开始使用富文本组件editor时,不知如何调用相关API设置富文本内容和获取内容,本文将举例详解 目录 一.了解editor组件的常用属性及相关API 1.属性常用说明 2.富文本相关API说明 1)editorContext 2) editorContext.setContents…

JAVA进化史: JDK8特性及说明

JDK 8(Java Development Kit 8)是Java平台的一个重大版本,于2014年3月发布。该版本引入了许多令人期待的新特性,其中一些改变了Java语言的面貌,提供了更丰富、灵活和现代的编程体验。以下是JDK 8的一些主要特性&#x…

线性投影(linear projection)

1、线性投影介绍 线性投影在数学、统计学、机器学习以及经济学等多个领域都有重要作用,其基本思想是将一个高维空间中的向量或点映射到该空间的某个子空间中。以下是线性投影的一些关键作用 1.1 维度降低(Dimensionality Reduction)&#xf…

【Leetcode】第 378 场周赛

文章目录 100166. 检查按位或是否存在尾随零题目题意代码 100185. 找出出现至少三次的最长特殊子字符串 I题目思路代码 100184. 找出出现至少三次的最长特殊子字符串 II 100166. 检查按位或是否存在尾随零 题目 题意 这里题目要求的是或运算,所以原数组中只需要有…

LeetCode每日一题.04(不同路径)

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例 1…

Spring Cloud + Vue前后端分离-第10章 基于阿里云OSS的文件上传

源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第10章 基于阿里云OSS的文件上传 前面介绍的文件上传是基于本地文件服务器的文件上传,但是自己搭文件服务器会有很多运维的问题,比如磁盘满了要扩容…

Spark SQL简介与基本用法

Apache Spark是一个强大的分布式计算框架,Spark SQL是其组件之一,用于处理结构化数据。Spark SQL可以使用SQL查询语言来查询和分析数据,同时还提供了与Spark核心API的无缝集成。本文将深入探讨Spark SQL的基本概念和用法,包括数据…

Flink Job 执行流程

Flink On Yarn 模式 ​ 基于Yarn层面的架构类似 Spark on Yarn模式,都是由Client提交App到RM上面去运行,然后 RM分配第一个container去运行AM,然后由AM去负责资源的监督和管理。需要说明的是,Flink的Yarn模式更加类似Spark on Ya…

Docker构建缓存

Docker镜像的分层结构 Docker的镜像是由一层一层的文件系统组成,以UnionFS(联合文件系统)堆叠构成Dockerfile中的每个指令都会创建一个新的镜像层镜像层将被缓存和复用当Dockerfile的指令修改了,复制的文件变化了,或者…

Linux环境安装1

一 概述 1.1 概要 模拟真实项目,碰到难题,使用技术/解决方案/架构设计思想;缓存架构,高并发;基于hystrix,缓存架构高可用的,高可用架构的设计以及相关的技术;商品详情页系统架构 -> 缓存架构 -> 高并发技术解决方案架构 -> 高可用技术解决方案…

【c++】遍历一棵树来获取信息,并根据这些信息用map生成另一棵树,新树的键是string类型,值是char*类型

主要思路 递归遍历一棵树&#xff0c;将获取的信息以键值对的形式存放到c的vector容器中&#xff0c;然后遍历vector容器中的键值对信息&#xff0c;利用map容器生成个另一棵树。 具体来说&#xff0c;就是使用std::pair<std::string, const char*>类型的向量infoVector来…

S7通信协议解析

我们以S7的1500系列来查看握手和读取、写入【字Word或者位Bit】命令报文 以下报文不做说明时都是十六进制字节。 西门子PLC需要连接成功后发送两次握手命令方可进行读写通信。 西门子PLC的S7协议的头由四个字节组成.。 第一个字节数固定为03,第二个字节数固定为00 第三个字…

掌握 C++ 中 static 关键字的多种使用场景

static是什么 在最开始C中引入了static关键字可以用于修饰变量和函数&#xff0c;后来由于C引入了class的概念&#xff0c;现在static可以修饰的对象分为以下5种&#xff1a; 成员变量&#xff0c;成员函数&#xff0c;普通函数&#xff0c;局部变量&#xff0c; 全局变量 s…

github Copilot的基本使用

一.GitHub Copilot的基本介绍 GitHub Copilot 是由 GitHub 和 OpenAI 合作推出的一款代码自动补全工具&#xff0c;它基GPT&#xff08;Generative Pre-trained Transformer&#xff09;技术&#xff0c;可以为程序员提供实时的代码提示和建议。以下是 GitHub Copilot 的基本使…

【leetcode】栈与队列总结

本文内容来自于代码随想录 栈 用栈实现队列 两个栈实现队列。思路&#xff1a;两个栈分别表示入栈和出栈。 入队&#xff1a;直接入栈出队&#xff1a; a. 出栈为空&#xff0c;先把入栈中的元素全部放到出栈中&#xff08;相当于反过来&#xff0c;这样在出栈的时候先进的元…

mysql间隙锁demo分析

概述 通常用的mysql都是innodb引擎&#xff1b; 一般在update的时候用id都会认为是给行记录加锁&#xff1b; 在使用非唯一索引更新时&#xff0c;会遇到临键锁&#xff08;范围锁&#xff09;&#xff1b; 临键锁和表中的数据有关&#xff1b; mysq版本:8 隔离级别&#xf…

SpringBoot整合mail进行发送邮箱

Spring Boot整合邮箱进行发送 1. 添加依赖 在pom.xml文件中添加spring-boot-starter-mail依赖&#xff0c;如下所示&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>…