文档章节

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

秋风醉了
 秋风醉了
发布于 2016/07/10 11:36
字数 1091
阅读 96
收藏 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=========

© 著作权归作者所有

共有 人打赏支持
秋风醉了
粉丝 236
博文 578
码字总数 419420
作品 0
朝阳
程序员
虚拟机对象

1.虚拟机对象的创建 虚拟机遇到new指令 (1) 类加载: 检查该指令参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载,解析和初始化过。如果没有,必须先...

Turnsole1
01/07
0
0
JavaScript面向对象编程实践

面向对象的几个概念 在进入正题前,先了解传统的面向对象编程(例如Java)中常会涉及到的概念,大致可以包括: 类:定义对象的特征。它是对象的属性和方法的模板定义。 对象(或称实例):类...

-波仔-
2016/03/22
11
0
Golang 学习笔记(09)—— json和xml解析

本文为转载,原文:Golang 学习笔记(09)—— json和xml解析 Golang xml package 函数 Marshal Marshal函数返回v的XML编码。 Marshal处理数组或者切片时会序列化每一个元素。Marshal处理指针...

ChainZhang
01/03
0
0
C++ 备忘录 ( 持续更新中... )

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

谷鹏
2011/04/12
0
1
NetHost指针访问安全专集(基于mdk1.10)

NetHost是服务器引擎的2大接口类之一,而且是由引擎维护其对象的创建与释放, 用户使用不当可能造成访问野指针或者内存泄露。 为了让使用mdk的朋友,安全的使用NetHost指针,本文写提出一些安...

火羽
2012/11/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Android WebView制作简易浏览器

最终效果 先创建一个WebView控件,其他的就是通过线性布局在上方加入网址输入框和两个按钮 <WebView android:id="@+id/act_webview_wv" android:layout_width="ma...

lanyu96
25分钟前
2
0
解决MacOS升级系统Sierra到Mojave后git报错

错误信息 升级MacOS Sierra到Mac Mojave后执行git命令报错: xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/......

阿dai
26分钟前
1
0
兄弟连区块链教程以太源码分析CMD深入分析(一)

cmd包分析 cmd下面总共有13个子包,除了util包之外,每个子包都有一个主函数,每个主函数的init方法中都定义了该主函数支持的命令,如 geth包下面的: func init() { // Initialize the...

兄弟连区块链入门教程
27分钟前
1
0
Titan Framework MongoDB深入理解1

在TitanFrameWork框架中,已经集成了MongoDB的各个功能,现在我们对框架内部的一些重要类进行分析与解读。 MongoDBConverter 在Titan框架中,比较重要的一个接口就是MongoDBConverter,它是作...

云季科技
32分钟前
1
0
SpringBoot集成Quartz

SpringBoot集成Quartz 什么是Quartz Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smalle......

Grittan
37分钟前
4
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部