第六章 Go方法

第三章中讲解了struct,面向对象编程OOP已经是一个编程范式了,Go语言同样支持OOP开发。

一个对象就是一个变量,在这个对象中包含了一些方法,一个方法是一个和特殊类型关联的函数。

函数function,是一段具有独立功能的代码,可以反复被调用

方法method,是一个类的行为功能,只有该类的对象才可以调用

一个Person结构体,除了有基本的字段(姓名、年纪、性别…等等),Person结构体还应该有一些行为动作,如(吃饭、说话、跑步、学习等…),这些事需要定义方法去完成。

Go的方法是作用在指定的数据类型上的,与数据类型绑定,自定义类型都可以有方法,不仅仅是struct。隐式的将struct实例作为第一实参(receiver)。

可以为当前包内的任意类型定义方法。

package main
type X int
func (x *X)inc(){ //方法前的变量参数x称作 receiver,作用类似python的self
*x++
}
func main(){
var x X
x.inc()
println(x)
}

1.1. 方法的声明和调用

package main

import "fmt"

//定义一个结构体数据类型
type Person struct {
Username string
Age int
Sex string
} //表示给Person结构体,绑定添加test方法
func (p Person) test() {
fmt.Println("通过p变量,取出结构体类型中的Username值是:", p.Username)
} func main() {
p1 := &Person{
"狗子",
18,
"男",
}
p1.test()
}

总结method

1.test方法和Person结构体类型绑定
2.test方法只能通过Person结构体的实例调用

语法

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

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

方法定义:

func (recevier type) methodName(参数列表)(返回值列表){}

参数和返回值可以省略
package main type Test struct{} // 无参数、无返回值
func (t Test) method0() { } // 单参数、无返回值
func (t Test) method1(i int) { } // 多参数、无返回值
func (t Test) method2(x, y int) { } // 无参数、单返回值
func (t Test) method3() (i int) {
return
} // 多参数、多返回值
func (t Test) method4(x, y int) (z int, err error) {
return
} // 无参数、无返回值
func (t *Test) method5() { } // 单参数、无返回值
func (t *Test) method6(i int) { } // 多参数、无返回值
func (t *Test) method7(x, y int) { } // 无参数、单返回值
func (t *Test) method8() (i int) {
return
} // 多参数、多返回值
func (t *Test) method9(x, y int) (z int, err error) {
return
} func main() {}

自定义数据类型绑定方法

package main

import (
"fmt"
) type Integer int func (i Integer) Print() {
fmt.Println("i的值:", i)
} func main() {
var a Integer
a = 1000
a.Print() var b int = 200
a = Integer(b)
a.Print()
}

1.2. 方法实战

package main

import "fmt"

//定义一个结构体数据类型
type Person struct {
Username string
Age int
Sex string
} //此时这个(p Person)就是一个接受者
//Person结构体,人是可以说话的,添加speak方法
func (p Person) speak() {
fmt.Printf("大声的喊出了自己的名字:%v\n", p.Username)
} //人还可以蹦跳
func (p Person) jump() {
fmt.Printf("%v:跳起来一拳打在了姚明的膝盖上\n", p.Username)
} //人还可以进行算数
//方法的参数列表与返回值列表,与函数一致
func (p Person) getSum(n1, n2 int) int {
sum := n1 + n2
fmt.Printf("%v:飞快的计算出%d+%d的结果是%d\n", p.Username, n1, n2, sum)
return sum
}
func main() {
p1 := &Person{
"李二狗",
18,
"男",
}
p1.speak()
p1.jump()
res := p1.getSum(1, 2)
fmt.Printf("p1.getSum方法返回值是%d\n", res)
}

1.3. 方法使用细节

1)结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式

2)如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理

3)当接受者不是一个指针时,该方法操作对应接受者的值的副本(意思就是即使你使用了指针调用函数,但是函数的接受者是值类型,所以函数内部操作还是对副本的操作,而不是指针操作。

package main

import "fmt"

type People struct {
Name string
Country string
} //此方法进行了值拷贝
func (p People) Print() {
fmt.Printf("我是谁:name=%s country=%s\n", p.Name, p.Country)
} //此方法进行了值拷贝,不会对p1进行修改
func (p People) Set(name string, country string) {
p.Name = name
p.Country = country
} //接收一个指针变量,可以修改原值
func (p *People) SetV2(name string, country string) {
p.Country = country
p.Name = name
} func main() {
var p1 People = People{
Name: "二狗子",
Country: "沙河",
} p1.Print()
//此处修改无效,并没有修改p1的原地址
p1.Set("二狗腿子", "日本")
p1.Print() //两者效果一样,是被编译器进行了优化
//(&p1).SetV2("people02", "english")
p1.SetV2("狗官", "日本")
p1.Print()
}

1.4. 方法和函数的区别

1.调用方式区别

函数调用:    函数名(参数列表)
方法调用: 变量名.方法名(参数列表)

2.对于普通函数,接受者为值类型时,不能将指针类型数据直接传递,传递时编译器就提示报错

package main

import "fmt"

func test(n1 int) int {
n1 = n1 + 10
return n1
} func test2(n1 *int) int {
*n1 = *n1 + 10
return *n1
} func main() {
var num = 10
//test函数接收的num有一个值拷贝的过程
res := test(num)
fmt.Println("值传递函数test结果:", res)
fmt.Println("值传递函数test修改num的结果:", num) //test2函数接收num变量的地址,因此修改的也是num的值
res1 := test2(&num)
fmt.Println("指针传递函数test2结果:", res1)
fmt.Println("值传递函数test2修改num的结果:", num)
}

3.对于方法(如struct的方法),接受者是值类型时,可以直接用指针类型变量调用方法,反之亦然。

package main

import "fmt"

type Person struct {
Name string
} func (p Person) test01() {
p.Name = "码云"
fmt.Printf("test01修改了name值:%v\n", p.Name)
} func (p *Person) test02() {
p.Name = "麻花藤"
fmt.Printf("test02修改了name值:%v\n", p.Name)
} func main() {
var p1 Person = Person{
"刘强东",
}
fmt.Println("p1默认值:", p1) //调用test01,由于值拷贝,并没有修改默认p1的Name值
//(&p1).test01() 即使传入地址,仍然进行了值拷贝
p1.test01()
fmt.Printf("此时main程序调用p1.test01,此时p1.Name值:%v\n", p1.Name) //传入地址
//可以简写p1.test02(),修改的是p1.Name原本内存地址
(&p1).test02()
fmt.Printf("main程序调用p1.test02,此时p1.Name值%v\n", p1.Name)
}

6.1Go方法的更多相关文章

  1. javaSE27天复习总结

    JAVA学习总结    2 第一天    2 1:计算机概述(了解)    2 (1)计算机    2 (2)计算机硬件    2 (3)计算机软件    2 (4)软件开发(理解)    2 (5) ...

  2. EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态

    本文目录 查看实体当前.原始和数据库值:DbEntityEntry 查看实体的某个属性值:GetValue<TValue>方法 拷贝DbPropertyValues到实体:ToObject ...

  3. mapreduce多文件输出的两方法

    mapreduce多文件输出的两方法   package duogemap;   import java.io.IOException;   import org.apache.hadoop.conf ...

  4. 【.net 深呼吸】细说CodeDom(6):方法参数

    本文老周就给大伙伴们介绍一下方法参数代码的生成. 在开始之前,先补充一下上一篇烂文的内容.在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作 ...

  5. IE6、7下html标签间存在空白符,导致渲染后占用多余空白位置的原因及解决方法

    直接上图:原因:该div包含的内容是靠后台进行print操作,输出的.如果没有输出任何内容,浏览器会默认给该空白区域添加空白符.在IE6.7下,浏览器解析渲染时,会认为空白符也是占位置的,默认其具有字 ...

  6. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  7. [C#] C# 基础回顾 - 匿名方法

    C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ...

  8. ArcGIS 10.0紧凑型切片读写方法

    首先介绍一下ArcGIS10.0的缓存机制: 切片方案 切片方案包括缓存的比例级别.切片尺寸和切片原点.这些属性定义缓存边界的存在位置,在某些客户端中叠加缓存时匹配这些属性十分重要.图像格式和抗锯齿等 ...

  9. [BOT] 一种android中实现“圆角矩形”的方法

    内容简介 文章介绍ImageView(方法也可以应用到其它View)圆角矩形(包括圆形)的一种实现方式,四个角可以分别指定为圆角.思路是利用"Xfermode + Path"来进行 ...

随机推荐

  1. Discuz的文件目录解析

    最近在学习discuz,对这个不了解的 可以参考 http://www.cnblogs.com/hgj123/p/4641845.html

  2. 对 ThreadLocal 的了解(一)

    Threadlocal ThreadLocal 在我个人理解范围内,主要作用是在同一个线程里面,去共享某个数据给这个线程在不同的阶段去使用. 本次使用范围 在集成 pageOffice 在线 word ...

  3. Django新手十个开发指导

    下面是关于Django新手开发中的一些建议,大家可以参考一下~~ 1,不要将项目名称包含在引用代码里 比如你创建了一个名为"project"的项目,包含一个名为"app& ...

  4. 自建Git服务器 - 创建属于你自己的代码仓库

    最近有线上朋友私信问我怎么搭建个人博客,也有咨询我个人项目的代码是如何保管的,还有一个朋友问我买了服务器玩了一段时间,等新鲜感过了就不知道做什么了. 关于这些问题并没有一个标准答案,每个人都有自己的使 ...

  5. tomcat启动日志中中文乱码

    场景 使用catalina.bat start命令启动tomcat7 方案 打开%catalina_home%/conf/logging.properties文件. 将其中的UTF-8代换为GBK. ...

  6. 【Linux常见问题】CentOS 6 root用户密码忘记,找回密码方法

    1.Linux的root密码修改不像Windows的密码修改找回,Windows的登录密码忘记需要介入工具进行解决.CentOS6和CentOS7的密码方法也是不一样的,具体如下: 2.centos ...

  7. Python 正则表达式——re模块介绍

    Python 正则表达式 re 模块使 Python 语言拥有全部的正则表达式功能,re模块常用方法: re.match函数 re.match从字符串的起始位置匹配,如果起始位置匹配不成功,则matc ...

  8. require.context的妙用

    比较好用,记录下来. 以下方法将获取vuex中Modules文件夹里的所有modules并导出. const files = require.context(".", false, ...

  9. 小猪的Python学习之旅 —— 16.再尝Python数据分析:采集拉勾网数据分析Android就业行情...

    一句话概括本文: 爬取拉钩Android职位相关数据,利用numpy,pandas和matplotlib对招人公司 情况和招聘要求进行数据分析. 引言: 在写完上一篇<浅尝Python数据分析: ...

  10. Nginx访问日志.Nginx日志切割

    11月27日任务 12.10 Nginx访问日志12.11 Nginx日志切割12.12 静态文件不记录日志和过期时间 1.Nginx访问日志 示例一: 日志格式 vim /usr/local/ngi ...