go-方法

总结: 感觉方法就是c++类的函数成员。

  1. 定义一个方法的形式就是普通的go函数定义前面再加个接收者参数,也就是这个方法属于的struct。
  2. 然后这个struct的定义和这个方法的声明必须在同一个包里面。
  3. 还有就是接收者参数可以是传值,也可以是传指针,传值只能改变副本的字段,而传指针可以改变原来那个struct的字段,再加个go的指向struct的指针可以隐式间接引用。
  4. 不管你接收者是指针还是值,你用指针还是值去调用这个方法,go的编译器都会给你重写这个调用过程,使得适用这个方法(比如接收者是指针,而你用值去调用,那么编译器会 (&p).func    )。

定义:方法只是个带接收者参数的函数。

理解:跟c++里面类的函数成员一个意思吧?不同struct的方法能够同名

tips:接收者的类型定义和方法声明必须在同一包内;不能为内建类型声明方法(除非给它一个别名)。

package main

import (
	"fmt"
)

type Myfloat float64
type Myint  int

func (f Myfloat) Abs() Myfloat{
	if f<0 {
		return -f
	} else{
		return f
	}
}

func (f Myint) Abs() int{
	if f<0 {
		return int(f)
	} else{
		return int(-f)
	}
}


func main(){

	var a Myfloat = 2.5
	var b Myint = 2

	fmt.Println(a.Abs(),"\n",b.Abs())  // 输出2.5 和-2 
}

指针接收者

你可以为指针接收者声明方法。

这意味着对于某类型 T,接收者的类型可以用 *T 的文法。(此外,T 不能是像 *int 这样的指针。(why 不可以,只要给个别名,在同一个包里面不就OK了吗?下面的例子就是)

指针接收者的方法可以修改接收者指向的值(而值接受者就不行,就跟c++的传值和传引用一样)。由于方法经常需要修改它的接收者,指针接收者比值接收者更常用。

tips:一个指向结构体的指针 p,我们可以通过 (*p).X 来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以。

若使用值接收者,那么 Scale 方法会对原始 Vertex 值的副本进行操作。(对于函数的其它参数也是如此。)Scale 方法必须用指针接受者来更改 main 函数中声明的 Vertex 的值。

使用指针接收者的原因有二:

首先,方法能够修改其接收者指向的值。

其次,这样可以避免在每次调用方法时复制该值。若值的类型为大型结构体时,这样做会更加高效。

// go-指南的例子
package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f  // 隐式间接引用
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	v.Scale(10)
	fmt.Println(v.Abs())
}


// 给内置类型 一个别名 实现指针接收者
type Myint  int

func (f Myfloat) Abs() Myfloat{
	if f<0 {
		return -f
	} else{
		return f
	}
}


func (f *Myint) Double() {
	*f=2*(*f)
}

func main(){


	var a Myint = 2
	a.Double()
	fmt.Println(a)
}

方法与指针重定向

带指针参数的函数必须接受一个指针:

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func ScaleFunc(v *Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}


var v Vertex
ScaleFunc(v, 5)  // 编译错误!
ScaleFunc(&v, 5) // OK

而以指针为接收者的方法被调用时,接收者既能为值又能为指针:

var v Vertex
v.Scale(5)  // OK
p := &v
p.Scale(10) // OK

对于语句 v.Scale(5),即便 v 是个值而非指针,带指针接收者的方法也能被直接调用。 也就是说,由于 Scale 方法有一个指针接收者,为方便起见,Go 会将语句 v.Scale(5) 解释为 (&v).Scale(5)

同样的事情也发生在相反的方向。

接受一个值作为参数的函数必须接受一个指定类型的值:

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func AbsFunc(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

var v Vertex
fmt.Println(AbsFunc(v))  // OK
fmt.Println(AbsFunc(&v)) // 编译错误!
 

而以值为接收者的方法被调用时,接收者既能为值又能为指针:

var v Vertex
fmt.Println(v.Abs()) // OK
p := &v
fmt.Println(p.Abs()) // OK

这种情况下,方法调用 p.Abs() 会被解释为 (*p).Abs()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值