方法篇
go指南地址:https://tour.go-zh.org/methods/1
1.方法
Go 没有类。然而,仍然可以在结构体类型上定义方法。
方法接收者 出现在 func 关键字和方法名之间的参数中。
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 main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
输出:
5
2.方法续
你可以对包中的 任意 类型定义任意方法,而不仅仅是针对结构体。
但是,不能对来自其他包的类型或基础类型定义方法
package main
import (
"fmt"
"math"
)
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-math.Sqrt2) //求二次根
fmt.Println(f.Abs())
}
输出:
1.4142135623730951
3.接收者为指针的方法
方法可以与命名类型或命名类型的指针关联。
刚刚看到的两个 Abs 方法。一个是在 *Vertex 指针类型上,而另一个在 MyFloat 值类型上。 有两个原因需要使用指针接收者。首先避免在每个方法调用中拷贝值(如果值类型是大的结构体的话会更有效率)。其次,方法可以修改接收者指向的值。
尝试修改 Abs 的定义,同时 Scale 方法使用 Vertex 代替 *Vertex 作为接收者。
当 v 是 Vertex 的时候 Scale 方法没有任何作用。Scale 修改 v。当 v 是一个值(非指针),方法看到的是 Vertex 的副本,并且无法修改原始值。
Abs 的工作方式是一样的。只不过,仅仅读取 v。所以读取的是原始值(通过指针)还是那个值的副本并没有关系。
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{
3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5) //结构体的值被Scale方法修改了,这里类的实现者Vertex传入的是指针; 如果是值拷贝,结构体内数据不会发生变化
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}
输出:
Before scaling: &{X:3 Y:4}, Abs: 5
After scaling: &{X:15 Y:20}, Abs: 25
接口篇
接口
接口类型是由一组方法定义的集合。
接口类型的值可以存放实现这些方法的任何值。
注意: 示例代码的 22 行存在一个错误。 由于 Abs 只定义在 *Vertex(指针类型)上, 所以 Vertex(值类型)不满足 Abser。
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat 实现了 Abser
a = &v // a *Vertex 实现了 Abser
// 下面一行,v 是一个 Vertex(而不是 *Vertex)
// 所以没有实现 Abser。
//a = v
fmt.Println(MyFloat(-math.Sqrt2).Abs()) //若方法不是通过调用指针实现的,可直接初始化类并且调用方法,结构体同上:fmt.Println(Vertex{3, 4}.Abs()) (如果Vertex不是通过指针调用的)
fmt.Println(a.Abs())
}
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 { //这里的方法的实现类的类型是指针,所以调用该方法时,也只能通过指针调用:v := Vertex{3, 4}; var a Abser = &v; fmt.Println(a.Abs())
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
输出:
1.4142135623730951
5
隐式接口
类型通过实现那些方法来实现接口。 没有显式声明的必要;所