文档章节

Go方法——基于对象指针的方法

秋风醉了
 秋风醉了
发布于 2016/07/10 11:36
字数 1091
阅读 103
收藏 1

Go方法——基于对象指针的方法

当调用一个函数时,会对其每一个参数值进行拷贝,如果一个函数需要更新一个变量,或者函数的其中一个参数实在太大我们希望能够避免进行这种默认的拷贝,这种情况下我们就需要用到指针了。对应到我们这里用来更新接收器的对象的方法,当这个接受者变量本身比较大时,我们就可以用其指针而不是对象来声明方法,如下:

package main

import (
	"fmt"
	"math"
)

func main() {

	// 三种调用方式
	r := &Point{1, 2} // 指针类型 r
	r.ScaleBy(2)      // 调用指针类型的方法
	fmt.Println(*r)   // "{2, 4}"

	p := Point{1, 2}
	pptr := &p      // 取地址符
	pptr.ScaleBy(2) // 通过指针调用方法
	fmt.Println(p)  // "{2, 4}"

	p := Point{1, 2}
	(&p).ScaleBy(2) // &p 获取 p的指针地址
	fmt.Println(p)  // "{2, 4}"

}

type Point struct{ X, Y float64 }

// traditional function
func Distance(p, q Point) float64 {
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// same thing, but as a method of the Point type
func (p Point) Distance(q Point) float64 {
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// 指针对象的方法,需要类型 Point 的指针调用该方法
// 这个方法的名字是(*Point).ScaleBy。这里的括号是必须的;没有括号的话这个表达式可能会被理解为*(Point.ScaleBy)。
func (p *Point) ScaleBy(factor float64) {
	p.X *= factor
	p.Y *= factor
}

上面代码演示了三种调用方式,如下,

// 三种调用方式
r := &Point{1, 2} // 指针类型 r
r.ScaleBy(2)      // 调用指针类型的方法
fmt.Println(*r)   // "{2, 4}"

p := Point{1, 2}
pptr := &p      // 取地址符
pptr.ScaleBy(2) // 通过指针调用方法
fmt.Println(p)  // "{2, 4}"

p := Point{1, 2}
(&p).ScaleBy(2) // &p 获取 p的指针地址
fmt.Println(p)  // "{2, 4}"

其实总结一点就是通过指针调用基于指针的方法。

但Go帮我们做了更多,帮我们简化了调用方式,如下示例,

package main

import (
	"fmt"
	"math"
)

func main() {
	// 更简便的调用方式
	pp := Point{4, 6} //pp 是Point 类型的变量
	pp.ScaleBy(2)     //直接用 Point 类型变量 pp 调用基于指针的方法也是可行的,是因为 Go 会隐式转换,自动转换为(&pp).ScaleBy(2)
	fmt.Println(pp)   // "{2, 4}"
}

type Point struct{ X, Y float64 }

// traditional function
func Distance(p, q Point) float64 {
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// same thing, but as a method of the Point type
func (p Point) Distance(q Point) float64 {
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// 指针对象的方法,需要类型 Point 的指针调用该方法
// 这个方法的名字是(*Point).ScaleBy。这里的括号是必须的;没有括号的话这个表达式可能会被理解为*(Point.ScaleBy)。
func (p *Point) ScaleBy(factor float64) {
	p.X *= factor
	p.Y *= factor
}

上面这段代码演示了使用 Point 类型的变量调用基于指针的方法时Go发生的隐式转换,其实使用 Point 类型的指针变量调用基于类型的方法Go也会自动隐式转换,如下,

package main

import (
	"fmt"
	"math"
)

func main() {
	pptr0 := &Point{1, 2}     //pptr0 指针类型
	p6 := Point{4, 6}         // Point 类型
	res := pptr0.Distance(p6) // 这里Go会发生隐式转换 自动转换为 (*pptr0).Distance(p6)
	fmt.Println(res)

}

type Point struct{ X, Y float64 }

// traditional function
func Distance(p, q Point) float64 {
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// same thing, but as a method of the Point type
func (p Point) Distance(q Point) float64 {
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

// 指针对象的方法,需要类型 Point 的指针调用该方法
// 这个方法的名字是(*Point).ScaleBy。这里的括号是必须的;没有括号的话这个表达式可能会被理解为*(Point.ScaleBy)。
func (p *Point) ScaleBy(factor float64) {
	p.X *= factor
	p.Y *= factor
}

总结:

  1. 不管你的method的receiver是指针类型还是非指针类型,都是可以通过指针/非指针类型进行调用的,编译器会帮你做类型转换(解引用和取地址)。
  2. 在声明一个method的receiver该是指针还是非指针类型时,你需要考虑两方面的内部,第一方面是这个对象本身是不是特别大,如果声明为非指针变量时,调用会产生一次拷贝;第二方面是如果你用指针类型作为receiver,那么你一定要注意,这种指针类型指向的始终是一块内存地址,就算你对其进行了拷贝。熟悉C或者C艹的人这里应该很快能明白。

=========END=========

© 著作权归作者所有

共有 人打赏支持
秋风醉了
粉丝 241
博文 566
码字总数 417505
作品 0
朝阳
程序员
私信 提问
block本质探寻六之修改变量

说明: <1>阅读本文章,请参照前面的block文章加以理解; <2>本文的变量指的是auto类型的局部变量(包括实例对象); <3>ARC和MRC两种模式均适用; 一、无法修改的原因 //代码 很明显,强行给...

春天里的花骨朵
昨天
0
0
本地方法怎么映射Java层的数据类型

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangyangzhizhou/article/details/79576578 前言 Java 语言上定义了不同的数据类型,比如有基础类型、等等,还...

超人汪小建(seaboat)
2018/03/16
0
0
虚拟机篇 之「运行时数据区域及虚拟机对象」

版权声明:Follow your heart and intuition. https://blog.csdn.net/qq_35246620/article/details/81431528 温馨提示:本系列博文(含示例代码)已经同步到 GitHub,地址为「java-skills」,...

维C果糖
2018/08/05
0
0
C++ 备忘录 ( 持续更新中... )

Tip 1: #include包含头文件的问题 新的编译器格式: #include <iostream>using namespace std; 旧的编译器格式: #include <iostream.h> 注:旧的编译器格式中,包含头文件后,不添加 “usi...

谷鹏
2011/04/12
0
1
block本质探寻五之atuto类型局部实例对象

说明:阅读本文章,请参考之前的block文章加以理解; 一、栈区block分析 //代码 //ARCvoid test1(){ } //打印 2019-01-14 17:24:12.118653+0800 MJ_TEST[6638:285938] Person dealloc2019-01...

春天里的花骨朵
前天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

echarts实现中国地图

最近项目中有个需求:在地图上展示各省市的数据分布,像这样: 项目中接入的图表展示工具是echart,查了echart官网,发现并没有中国地图相关的实现,唯一接近的,只有香港18区人口密度。没办...

Funcy1122
32分钟前
2
0
持续集成工具Jenkins结合SVN的安装和使用

持续集成工具Jenkins结合SVN的安装和使用 2018年06月08日 11:30:23 止步前行 阅读数:2932 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxd1435513775/ar...

linjin200
39分钟前
1
0
ES6 对象的解构赋值

基本用法 1.等号右边如果不是数组,将会报错(不是可遍历结构) 2.解构赋值 var, let, const命令声明均适用 3.set结构也可解构赋值(具有Iterator接口,可采用数组形式结构赋值) set解构:任何...

Jack088
41分钟前
3
0
微信小程序富文本table超出宽度处理

一、微信小程序富文本table超出宽度处理 处理思路: 使用正则删除table中的width属性。 //去除table的宽度content = content.replace(/<table[^>]*>/gi, function (match, capture) { ...

tianma3798
43分钟前
2
0
阿里云全站加速DCDN全面支持WebSocket协议

WebSocket协议可以为网站和应用提供真正的双向通信,具有控制开销、保持连接状态、更强实时性、更好的压缩效果等优点,是当下低延时应用最常采用的一种技术协议。为了更好的满足客户在实时通...

阿里云官方博客
44分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部