第六章 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. AtomineerUtils使用说明

    AtomineerUtils使用说明 VS2015PluginCrackAtomineer 介绍 AtomineerUtils 是国外的一款用于生成源代码注释的一款 VS 插件工具. 这款插件,支持 ...

  2. JDK 14的新特性:更加好用的NullPointerExceptions

    JDK 14的新特性:更加好用的NullPointerExceptions 让99%的java程序员都头痛的异常就是NullPointerExceptions了.NullPointerExceptio ...

  3. Linux运维基础阶段部分复习概要

    [jj@oldboy ~]$ hostnamectl set-hostname zj 主机名只有root用户才有权限修改,普通用户想要修改要知道root密码,sudo提权,重启虚拟机或者打开新的窗口新 ...

  4. FastJson踩坑:@JsonField在反序列化时失效

    问题描述 一个对象(某个字段为枚举类型,为了不采用默认的序列化过程,用@JSONField指定了序列化器和反序列器,过程见旧博文),将其放到JSONArray中再序列化JSONArray对象,用得到的 ...

  5. JavaScript面向对象那些东西-继承

    继承 父类里有些属性方法 子类想把父类中的这些属性方法 继承过来给子类自己的实例也用用 ( ps: →_→ 能不能专业点 没文化真可怕 ) 一.原型链继承 // 原型链继承:把子类的原型作为父类的实例 ...

  6. WebStorm 2019 3.3 安装及破解教程附汉化教程

    WebStorm2019 3.3 安装及破解教程附加汉化教程 安装包及破解补丁 链接: https://pan.baidu.com/s/19ATTAW3Tsm0huIJSqYChTw 提取码:1ei7 ...

  7. vue做商品选择如何保持样式

    是这样的情况:我知道,在vue里,实现点击高亮,可以使用诸如: <div class="static" v-bind:class="{defaultClass ,a ...

  8. ACM周记

    放假一周了,虽然知识都学完了,但是使用和会用还是很难,不能在按着这个情形发展下去,这样的话肯定完成不了自己的任务,所以必须要改变自己的学习方法和学习态度,学习态度,一个星期也睡够放松够了,也玩够了,该 ...

  9. .Net Core中使用Dapper构建泛型仓储

    前言:Dapper是.NET的简单对象映射器,在速度方面拥有ORM之王的称号,与使用原始ADO.NET读取数据一样快.ORM是对象关系映射器,它负责数据库和编程语言之间的映射. 仓储主要是用来解耦业务 ...

  10. 关于2020.04.26【MySQL导出数据到文件中的方法】的补充

    之前导出的数据文件中没有表的列名,感觉不够完整,摸索一下发现带表列名导出也是可以的,只试了导出txt和csv两种文件类型的方法.       1.导出数据到txt文件中(包含数据表列名)的方法:先选择 ...