iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang通脉之方法详情
  • 230
分享到

Golang通脉之方法详情

2024-04-02 19:04:59 230人浏览 八月长安
摘要

目录方法和接收者指针类型的接收者值类型的接收者方法和函数任意类型添加方法方法继承方法重写结构体和方法补充方法和接收者 Go语言中的方法(Method)是一种作用于特定类型变量的函数

方法和接收者

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。

Go 语言中同时有函数和方法。一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集

方法只是一个函数,它带有一个特殊的接收器类型,它是在func关键字和方法名之间编写的。接收器可以是struct类型或非struct类型。接收方可以在方法内部访问。

方法能给用户自定义的类型添加新的行为。它和函数的区别在于方法有一个接收者,给一个函数添加一个接收者,那么它就变成了方法。接收者可以是值接收者,也可以是指针接收者。

在调用方法的时候,值类型既可以调用值接收者的方法,也可以调用指针接收者的方法;指针类型既可以调用指针接收者的方法,也可以调用值接收者的方法。

也就是说,不管方法的接收者是什么类型,该类型的值和指针都可以调用,不必严格符合接收者的类型。

方法的定义格式如下:


func (t Type) methodName(parameter)(return) {
  
}

其中

  • t:接收者中的参数变量名在命名时,官方建议使用接收者类型名称首字母的小写,而不是selfthis之类的命名。
  • Type:接收者类型和参数类似,可以是指针类型和非指针类型。
  • methodNameparameter return :具体格式与函数定义相同。

//Person 结构体
type Person struct {
 name string
 age  int8
}
 
//NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
 return &Person{
  name: name,
  age:  age,
 }
}
 
//Dream Person做梦的方法
func (p Person) Dream() {
 fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}
 
func main() {
 p1 := NewPerson("张三", 25)
 p1.Dream()
}


方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。

可以定义相同的方法名:


type Rectangle struct {
 width, height float64
}
type Circle struct {
 radius float64
}
 
 
func (r Rectangle) area() float64 {
 return r.width * r.height
}
//该 method 属于 Circle 类型对象中的方法
func (c Circle) area() float64 {
 return c.radius * c.radius * math.Pi
}
func main() {
 r1 := Rectangle{12, 2}
 r2 := Rectangle{9, 4}
 c1 := Circle{10}
 c2 := Circle{25}
 fmt.Println("Area of r1 is: ", r1.area())
 fmt.Println("Area of r2 is: ", r2.area())
 fmt.Println("Area of c1 is: ", c1.area())
 fmt.Println("Area of c2 is: ", c2.area())
}

运行结果:

Area of r1 is:  24
Area of r2 is:  36
Area of c1 is:  314.1592653589793
Area of c2 is:  1963.4954084936207

  • 虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样
  • method里面可以访问接收者的字段
  • 调用method通过.访问,就像struct里面访问字段一样

指针类型的接收者

指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。这种方式就十分接近于其他语言中面向对象中的this或者self


type Rectangle struct {
 width, height int
}
 
func (r *Rectangle) setVal() {
 r.height = 20
}
 
func main() {
 p := Rectangle{1, 2}
 s := p
 p.setVal()
 fmt.Println(p.height, s.height)
}

结果:

20 2

值类型的接收者

当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。


type Rectangle struct {
 width, height int
}
 
func (r Rectangle) setVal() {
 r.height = 20
}
 
func main() {
 p := Rectangle{1, 2}
 s := p
 p.setVal()
 fmt.Println(p.height, s.height)  // 2 2
}

什么时候应该使用指针类型接收者

  • 需要修改接收者中的值
  • 接收者是拷贝代价比较大的大对象
  • 保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

方法和函数

已经有了函数,为什么还要使用方法?


type Employee struct {  
    name     string
    salary   int
    currency string
}
 

func displaySalary(e Employee) {  
    fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}
 
func main() {  
    emp1 := Employee{
        name:     "Sam Adolf",
        salary:   5000,
        currency: "$",
    }
    displaySalary(emp1)
}

在上面的程序中,displaySalary方法被转换为一个函数,而Employee struct作为参数传递给它。这个程序也产生了相同的输出:Salary of Sam Adolf is $5000.。

为什么可以用函数来写相同的程序呢?有以下几个原因:

Go不是一种纯粹面向对象的编程语言,它不支持类。因此,类型的方法是一种实现类似于类的行为的方法。
相同名称的方法可以在不同的类型上定义,而具有相同名称的函数是不允许的。

任意类型添加方法

在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法。


//MyInt 将int定义为自定义MyInt类型
type MyInt int
 
//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
 fmt.Println("Hello, 我是一个int。")
}
func main() {
 var m1 MyInt
 m1.SayHello() //Hello, 我是一个int。
 m1 = 100
 fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt
}

注意事项: 非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。

方法继承

方法是可以继承的,如果匿名字段实现了一个方法,那么包含这个匿名字段的struct也能调用该方法


type Human struct {
 name  string
 age   int
 phone string
}
type Student struct {
 Human  //匿名字段
 school string
}
type Employee struct {
 Human   //匿名字段
 company string
}
 
func (h *Human) SayHi() {
 fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func main() {
 mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
 sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "golang Inc"}
 mark.SayHi()
 sam.SayHi()
}

运行结果:


Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam you can call me on 111-888-XXXX

方法重写


type Human struct {
 name  string
 age   int
 phone string
}
type Student struct {
 Human  //匿名字段
 school string
}
type Employee struct {
 Human   //匿名字段
 company string
}
 
//Human定义method
func (h *Human) SayHi() {
 fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
 
//Employee的method重写Human的method
func (e *Employee) SayHi() {
 fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
  e.company, e.phone) //Yes you can split into 2 lines here.
}
func main() {
 mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
 sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
 mark.SayHi()
 sam.SayHi()
}



运行结果:

Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX

  • 方法是可以继承和重写的
  • 存在继承关系时,按照就近原则,进行调用

结构体和方法补充

因为slicemap这两种数据类型都包含了指向底层数据的指针,因此在需要复制它们时要特别注意:


type Person struct {
 name   string
 age    int8
 dreams []string
}
 
func (p *Person) SetDreams(dreams []string) {
 p.dreams = dreams
}
 
func main() {
 p1 := Person{name: "张三", age: 18}
 data := []string{"吃饭", "睡觉", "打豆豆"}
 fmt.Printf("%p\n",data)  //0xc00006e360
 p1.SetDreams(data)      //传的是 data 的内存地址,此时p.dreams和data指向同一块内存空间
 fmt.Printf("%p\n",p1.dreams) //0xc00006e360
 
 // 你真的想要修改 p1.dreams 吗?
 data[1] = "不睡觉"    //data值的修改会影响person结构体的dream字段
 fmt.Println(p1.dreams)  // [吃饭 不睡觉 打豆豆]
}

正确的做法是在方法中使用传入的slice的拷贝进行结构体赋值。


func (p *Person) SetDreams(dreams []string) {
 p.dreams = make([]string, len(dreams))
 copy(p.dreams, dreams)
}


同样的问题也存在于返回值slicemap的情况,在实际编码过程中一定要注意这个问题。

到此这篇关于Golang通脉方法详情的文章就介绍到这了,更多相关Golang通脉方法内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Golang通脉之方法详情

本文链接: http://www.lsjlt.com/news/155176.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Golang通脉之方法详情
    目录方法和接收者指针类型的接收者值类型的接收者方法和函数任意类型添加方法方法继承方法重写结构体和方法补充方法和接收者 Go语言中的方法(Method)是一种作用于特定类型变量的函数...
    99+
    2024-04-02
  • Golang通脉之map详情
    目录1、定义2、基本使用3、判断键是否存在4、map的遍历5、delete()函数删除map元素6、指定顺序遍历map7、map类型的切片8、value为切片类型的map9、map是...
    99+
    2024-04-02
  • Golang通脉之流程控制详情
    目录1、if else(分支结构)1.1 if条件判断基本写法1.2 if条件判断特殊写法2、for(循环结构)2.1 无限循环3、for range(键值循环)4、switch c...
    99+
    2024-04-02
  • Golang通脉之数据类型详情
    目录1、标识符与关键字1.1 标识符1.2 关键字2、变量2.1 什么是变量2.2 变量类型2.3 变量声明3、常量3.1 iota4、基本数据类型4.1 整型4.2 浮点型4.3 ...
    99+
    2024-04-02
  • Golang通脉之类型定义
    目录1、自定义类型2、类型定义2.1 定义结构体2.2 定义接口2.3 定义其他的新类型2.4 定义函数的类型3、类型别名4、类型定义和类型别名的区别5、非本地类型不能定义方法6、在...
    99+
    2024-04-02
  • Python黑魔法之metaclass详情
    目录一、什么是 metaclass二、metaclass 能解决什么问题?三、通过一个实例来理解 metaclass四、Python 底层语言设计层面是如何实现 metaclass ...
    99+
    2024-04-02
  • golang生成vcf通讯录格式文件详情
    目录1.源码​2.源码解析3.运行结果前言: vcf文件:​VCF是通讯录格式文件,一般需要用手机通讯录导入导出的文件格式都是vcf格式。​ 目的:​如果你是卖房销售,或者你是做什么...
    99+
    2024-04-02
  • Golang函数方法详解:入门到精通
    Golang(Go语言)作为一种新兴的编程语言,受到了越来越多开发者的青睐。其简洁、高效的特点,使得它成为了许多项目中的首选语言。在Golang中,函数是非常重要的概念,通过函数可以实...
    99+
    2024-03-13
    方法 函数 golang go语言
  • python中__init__()方法详情
    python类中定义的函数称为方法, init ()方法本质也是一个函数。这个函数的作用是初始化实例后的对象。 具体如下例: init()方法的作用是初始化实例后的对象cq...
    99+
    2024-04-02
  • golang 通用Contains方法分享
    今天在群里看见有人写了一个InAarry方法,主要作用是判断一个元素是否在slice中,看完后,我感觉方法应该还有扩展的空间 于是自己重新写了一个Contains方法 可以支持 sl...
    99+
    2024-04-02
  • Golang文件读取的方法详解:从入门到精通
    Golang文件读取的方法详解:从入门到精通 Golang是一种有着强大且高效的编程语言,被广泛应用于云计算、大数据和网络编程等领域。在这些应用场景中,文件读取是一项基本的操作。本文将介绍Golang的文件读...
    99+
    2024-01-19
    Golang 文件读取 精通
  • Golang拾遗之自定义类型和方法集详解
    golang拾遗主要是用来记录一些遗忘了的、平时从没注意过的golang相关知识。 很久没更新了,我们先以一个谜题开头练练手: package main import ( ...
    99+
    2023-02-20
    Golang自定义类型 方法集 Golang自定义类型 Golang 方法集
  • JavaScript中Set集合的方法详情
    目录Set集合概述如何创建并使用 SetAdd()Clear()Delete()Entries()Has()ForEach()Keys() 与 values()SizeSe...
    99+
    2024-04-02
  • Java字符串逆序方法详情
    目录1.简述2.代码实现1.简述 记录下实现字符串逆序的两种方法: 第一种方法比较暴力,通过字符串的下标将字符串逆转过来,这里要用到String类的substring()方...
    99+
    2024-04-02
  • JavaScript常用方法和封装详情
    目录1.字符串相关1.1 format方法2.数组相关1.2 forEach(callback,context) 操作数组中的每一个元素1.3 indexOf(searchvalue...
    99+
    2024-04-02
  • vue中Promise的使用方法详情
    目录一、使用1.promise是一种异步解决方案2.async await简介: promise是什么,它可以说是异步编程的一种解决方法,就拿传统的ajax发请求来说,单个还好,如果...
    99+
    2024-04-02
  • Java中API的使用方法详情
    目录1.API1.1API概述1.2API帮助文档的具体使用2.String类2.1String类概述2.2String类的特点2.3String类的构造方法2.4创建字符串对象两种...
    99+
    2024-04-02
  • Golang并发之RWMutex的用法详解
    目录前言RWMutexRWMutex 结构体介绍简单读写场景示例基于 RWMutex 实现一个简单的协程安全的缓存RWMutex 易错场景没有正确的加锁和解锁重复加锁读操作内嵌写操作...
    99+
    2023-05-14
    Golang并发RWMutex Golang RWMutex Go RWMutex
  • Java线程通信之wait-notify通信方式详解
    目录1.线程通信的定义2.为什么需要wait-notify3.wait方法和notify方法1、对象的wait()方法2、对象的notify()方法4.wait方法和notify方法...
    99+
    2024-04-02
  • Vue插件使用方法详情分享
    目录一.应用场景二.使用方法1.使用自定义插件2.使用第三方插件【elementUI】一.应用场景 为vue添加全局功能,比如添加全局的方法和属性、混入全局组件、添加全局资源(指令、...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作