Golang——方法

一. 方法定义

        Golang方法总是绑定对象的实例,并隐式将实例作为第一实参。

  • 只能为当前包内命名类型定义方法
  • 参数receiver可以任意命名。如方法中未曾使用,可省略参数名
  • 参数receiver类型可以是T或*T。基类型T不能是接口或指针类型(即多级指针)
  • 不支持方法重载,receiver只是参数前面的组成部分
  • 可用实例value或pointer调用全部方法,编译器自动转换

        一个方法就是一个包含接收者(receiver)的函数,接收者(receiver)可以是命名类型或者结构体类型的一个值或者是一个指针。

        所有给定类型的方法属于该类型的方法集。

        1.1 方法定义

func (reveicer type) methodName(参数列表)(返回值列表){}//参数和返回值可以省略
package maintype test struct{}// 接收者为值类型,无参,无返回值
func (t test) method0() {}// 接收者为值类型,单参,无返回值
func (t test) method1(x int) {}// 接收者为值类型,无参,单返回值
func (t test) method2() (res int) { return }// 接收者为值类型,多参,无返回值
func (t test) method3(x, y int) {}// 接收者为值类型,无参,多返回值
func (t test) method4() (res1, res2 int) { return }// 接收者为值类型,多参,多返回值
func (t test) method5(x, y int) (res1, res2 int) { return }// 接收者为指针类型,无参,无返回值
func (t *test) method6() {}// 接收者为指针类型,单参,无返回值
func (t *test) method7(x int) {}// 接收者为指针类型,无参,单返回值
func (t *test) method8() (res int) { return }// 接收者为指针类型,多参,无返回值
func (t *test) method9(x, y int) {}// 接收者为指针类型,无参,多返回值
func (t *test) method10() (res1, res2 int) { return }// 接收者为指针类型,多参,多返回值
func (t *test) method11(x, y int) (res1, res2 int) { return }func main(){}

下面定义了一个结构体类型和它的方法。

        解释:首先我们定义了一个叫做User的结构体类型,然后定义了一个该类型的方法Notice,该方法的接收者是一个User类型的值。要调用Notice方法,我们需要一个User类型的值或者指针。 

        在例子中,当我们使用指针时,Go调整成解引用使得调用可以被执行。

        注意:当接收者不是一个指针时,该方法操作对应接收者值的副本。意思是即使你使用指针调用方法,但方法的接收者是值类型,方法内部的操作还是对副本进行操作,不会修改原来的值。

         我们修改Notice方法,让他的接收者变成指针类型。

        注意:当接收者是指针,即使使用值类型调用方法,方法内部也是对指针操作。会修改原来的值。

  • 方法不过是特殊的函数,只需要将其还原,就知道receiver T和*T的差别

        1.2 普通函数与方法区别

  • 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
  • 对于方法,接收者为值类型,可以直接使用指针类型的变量调用方法,反过来也可以。
package mainimport "fmt"//普通函数
//接收者为值类型
func valueIntTest(a int) int {return a + 10
}//接收者为指针类型
func pointIntTest(a *int) int {return *a + 10
}func testValue() {a := 10fmt.Println(valueIntTest(a))//不能传递指针 如:valueIntTest(&a)b := 20fmt.Println(pointIntTest(&b))//不能传递值 如:pointIntTest(b)
}//结构体
type Data struct {x int
}func (d Data) valueShowData() {fmt.Println(d.x)
}func (d *Data) pointShowData() {fmt.Println(d.x)
}func testStruct() {//值类型调用方法d1 := Data{x: 10}d1.valueShowData()d1.pointShowData()//指针类型调用方法d2 := &Data{x: 100}d2.valueShowData()d2.pointShowData()
}func main() {testValue()testStruct()
}

二. 匿名字段

        Golang匿名字段:可以像字段成员那样访问匿名字段方法,编译器负责查找。

        Go语言是通过嵌套来实现继承的,依据编译器查找次序,只需要在外层定义同名方法,就可以实现继承的隐藏。

三. 方法集

        Golang的方法集:每个类型都有与之关联的方法集,这会影响到接口的实现规则。

  • 类型T方法集包含全部receiver T的方法
  • 类型*T方法集包含全部receiver T + *T方法
  • 如类型S包含匿名字段T,则S和*S方法集包含T的方法
  • 如类型S包含匿名字段*T,则S和*S方法集包含T + *T方法
  • 不管嵌入T或*T,*S方法集总是包含T + *T方法

        用实例value和pointer调用方法(含其它自定义类型)不受方法集的约束,编译器总是查找全部方法,并自动转换reveiver实参。

        方法集和调用方法没有关系。方法集是Go语言中实现面向对象编程特性的关键概念之一,它允许开发者为自定义类型定义行为,并通过接口来实现多态。同时,方法集也是Go语言类型系统和接口系统中不可或缺的一部分。

  • Go语言中内部类型方法提升的规则

        类型T方法集包含全部receiver T的方法。

        类型*T方法集包含全部receiver T + *T方法。

        给定结构体类型S和一个命名为T的类型,方法提升像下面规定的这样被包含在结构体方法集中:

        如类型S包含匿名字段T,则S和*S方法集包含T方法。

        这条规则说的是当我们嵌入一个值类型嵌入类型的接收者为值类型的方法将被提升,可以被外部类型的值和指针调用。

        如类型S包含匿名字段*T,则S和*S方法集包含T+*T方法。

        这条规则说的是当我们嵌入一个类型的指针,嵌入类型的接收者为值类型或者指针类型的方法将被提升,可以被外部类型的值或指针调用

四. 表达式

        Golang表达式:根据调用者不同,方法分为两种表现形式。

  1. object.method(arg...)
  2. type.method(arg...)

        前者称为method value,后者method expression。两者都可像普通函数那样赋值和传参,区别在于method value绑定实例,而method expression则需显示传参。

  •  method value会复制receiver

在汇编层面上,method value和闭包的实现方式相同,实际返回FuncVal类型对象。

FuncVal { method_address, receiver_copy }
  • 可依据方法集转换method expression,注意receiver类型的差异

  • 将方法还原成函数,就是下面的代码
package maintype User struct{}func (User) TestValue() {}func (*User) TestPoint() {}func main() {var u *User = nilu.TestPoint()(*User)(nil).TestPoint() //method value,对象为nil(*User).TestPoint(nil)   //method expression,传的对象为nil
}

五. 自定义error

        5.1 抛异常和处理异常

        5.1.1 抛异常

package mainimport "fmt"//系统抛异常
func test01() {a := [5]int{1, 2, 3, 4}a[1] = 123fmt.Println(a)index := 10a[index] = 10fmt.Println(a)
}func getCircleArea(radius float32) float32 {if radius < 0 {panic("半径不能为负") //自己抛异常}return 3.14 * radius * radius
}func test02() {getCircleArea(-5)
}//捕获异常
func test03() {//回收异常defer func() {if err := recover(); err != nil {fmt.Println(err)}}()test02()fmt.Println("这里不执行")
}func test04() {test03()fmt.Println("test04")
}func main() {test04()test01()
}

        5.1.2 返回异常

        5.2 自定义错误

 

 

 

        

 

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

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

相关文章

【随笔】Git 高级篇 -- 相对引用2 HEAD~n(十三)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

【算法详解】二分查找

1. 二分查找算法介绍 「二分查找算法&#xff08;Binary Search Algorithm&#xff09;」&#xff1a;也叫做 「折半查找算法」、「对数查找算法」。是一种在有序数组中查找某一特定元素的搜索算法。 基本算法思想&#xff1a;先确定待查找元素所在的区间范围&#xff0c;在逐步…

ROS通信机制---服务通信

2.2服务通信 2.2.1服务通信理论模型 2.2.2服务通信自定义srv 后续调用相关msg时&#xff0c;是从这些中间文件调用的 2.2.3服务通信自定义srv调用A&#xff08;c&#xff09; 1.服务端 2.客户端 实现参数的动态提交 问题&#xff1a;如果先启动客户端&#xff0c;那么会请求异…

避雷!网络安全学习五大误区,你还不知道?

尽管安全问题老生常谈&#xff0c;但一些普遍存在的误区仍然可能让企业随时陷入危险境地。 为了有效应对当前层出不穷且不断变换的网络威胁&#xff0c;最大程度规避潜在风险&#xff0c;深入了解网络安全的发展趋势必不可少。即使部署了最新且最先进的硬件和解决方案并严格遵守…

技能鉴定试题及答案,分享几个实用搜题和学习工具 #其他#职场发展

市面上搜题软件不少&#xff0c;大部分都挺好用的&#xff0c;今天小编在这里给大家分享几个好用的搜题工具&#xff0c;都拥有丰富的题库资源&#xff1b;而且搜题功能也都很完善&#xff0c;手机端、网页端均有&#xff0c;有需要的小伙伴赶紧码住&#xff01; 1.千鸟搜题 …

配置VM开机自启动

1. 在此电脑-右键选择“管理”-服务和应用程序-服务中找到VMware Workstation Server服务&#xff08;新版名称也可能是VMware自启动服务&#xff0c;自己找一下&#xff0c;服务属性里有描述信息的&#xff09;&#xff0c;将其启用并选择开机自动启动 新版参考官方文档&…

Redis Cluster集群模式

目录 一、理论 1.1 概念 1.2 集群的作用 1.3 redis集群的数据分片 1.4 Redis集群的主从复制模型 二、实践 2.1 Redis集群模式的搭建 2.1.1 cluster集群前期工作 2.1.2 开启群集功能 2.1.3 启动redis节点 2.1.4 启动集群 2.2 测试集群 总结 一、理论 1.1 概念 集群&a…

SpringBoot及其特性

0.前言 Spring 框架提供了很多现成的功能。那么什么是 Spring Boot&#xff1f;使用 Spring 框架&#xff0c;我们可以避免编写基础框架并快速开发应用程序。为了让 Spring 框架提供基础框架&#xff0c;我们需要向 Spring 框架描述有关我们的应用程序及其组件的信息。 不只是…

混合云构建-如何通过Site to Site VPN 连接 AWS 和GCP云并建立一个高可用的VPN通信

如果我们的业务环境既有AWS云又有GCP云,那么就需要将他们打通,最经济便捷的方式就是通过Site-to-Site VPN连接AWS和GCP云,你需要在两个云平台上分别配置VPN网关,并建立一个VPN隧道来安全地连接这两个环境,稍微有些复杂繁琐,以下是详细步骤的动手实践: 一、在GCP 云中创…

深入了解iOS内存(WWDC 2018)笔记-内存诊断

主要记录下用于分析iOS/macOS 内存问题的笔记。 主要分析命令&#xff1a; vmmap, leaks, malloc_history 一&#xff1a;前言 有 3 种思考方式 你想看到对象的创建吗&#xff1f;你想要查看内存中引用对象或地址的内容吗&#xff1f;或者你只是想看看 一个实例有多大&#…

LiveGBS流媒体平台GB/T28181常见问题-系统服务日志如何配置日志个数日志路径日志时长web操作日志操如何配置保留天数及过滤

LiveGBS系统服务日志如何配置日志个数日志路径日志时长web操作日志操如何配置保留天数及过滤 1、系统服务日志1.1、日志目录1.2、配置日志文件个数及记录时间1.3、配置日志文件路径 2、Web 操作日志2.1、配置保留天数2.2、配置不记录操作日志2.1.1、不记录所有2.1.2、不记录指定…

JS与Python函数在语法的区别

区别 标题语法&#xff1a;Python使用缩进来表示代码块&#xff0c;而JavaScript使用大括号{}。 Python函数定义&#xff1a; def my_function():# 函数体JavaScript函数定义&#xff1a; function myFunction() {// 函数体 }标题参数传递&#xff1a;Python支持位置参数、…