Go方法——基于对象指针的方法
Go方法——基于对象指针的方法
秋风醉了 发表于2年前
Go方法——基于对象指针的方法
  • 发表于 2年前
  • 阅读 67
  • 收藏 1
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

摘要: Go方法——基于对象指针的方法

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=========

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 216
博文 604
码字总数 431105
×
秋风醉了
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: