从零开始学Go之函数(二):指针与方法
类型别名与类型定义:
类型别名:
type 类型别名 = 类型名
type TypeAlias = int
TypeAlias 只是 int 的别名,本质上 TypeAlias 与 int 是同一个类型
类型定义:
type 新类型名 类型
type NewInt int
NewInt 则是一个新的类型,虽然他的实例化可以被赋值int,但是不再是int
方法:
Go 没有类。不过你可以为结构体类型或者非结构体类型定义方法。
方法就是一类带特殊的接收者参数的函数。
func (方法名 类型定义名) 函数名 (函数参数列表) (函数返回值列表){
函数内部代码
}
type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } type MyInt int func (i MyInt) Abs() int { if i < 0 { return int(-i) } return int(i) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs()) i := MyInt(-2) fmt.Println(i.Abs()) }
运行结果:
5
-2
此时,只有当实例化后,才能调用Abs()函数。两个Abs()函数对应的类型是不同的,所以调用的结果也不同
方法只是个带接收者参数的函数。
指针:
简单解释一下,每个变量在运行时都会有一个在内存中的地址,而指针就是存储这个地址。
声明:
var [指针名] *[指针类型]
var p *int//一个int类型的指针
操作:
从指针取值:取地址操作符“&”
从值取地址:取值操作符“*”
使用例子:
func main() { var a int a = 1 var b *int //或者是b:=new(int) 声明整型指针b b = &a //b保存a的地址,即b指向a fmt.Println("a value=", a) fmt.Println("a address=", &a) fmt.Println("b address=", b) fmt.Println("b value=", *b) *b = 3 //通过指针修改值 fmt.Println("a value=", a) fmt.Println("a address=", &a) fmt.Println("b address=", b) fmt.Println("b value=", *b) } a value= 1 a address= 0xc0420080a8 b address= 0xc0420080a8 b value= 1 a value= 3 a address= 0xc0420080a8 b address= 0xc0420080a8 b value= 3
可以发现地址没有改变,但是a和*b的值都同时改变了,由于b此时保存的是a的地址,当改变*b的值的时候实际就是在改变a的值。
方法的指针:
对于上一种方法,由于在函数中复制的是值,而本身没有改变,所以当需要改变实例化的结构体本身时,需要改变为方法的指针。
func (方法名 *类型定义名) 函数名 (函数参数列表) (函数返回值列表){
函数内部代码
}
type Vertex struct { X, Y float64 } func (v Vertex) Abs() float64 { v.X=6 v.Y=8 return math.Sqrt(v.X*v.X + v.Y*v.Y) } func (v *Vertex) NewAbs() float64 { v.X=6 v.Y=8 return math.Sqrt(v.X*v.X + v.Y*v.Y) } func main() { v := Vertex{3, 4} fmt.Println(v.Abs(), v) fmt.Println(v.NewAbs(), v)//v的值已经改变 }
运行结果:
10 {3 4}
10 {6 8}
这里需要注意的是NewAbs()中方法接收者是指针,虽然main函数中接受者v不是地址,但是Go会自动解释为(&v).NewAbs()