方法

``````// 类
type Point struct {X, Y int}
// 对象
p := Point{1, 2}
// 方法 即绑定在struct上的函数
// ...

方法声明

``````package main

import (
"fmt"
"math"
)

type Point struct {
X, Y float64
}

func (p Point) Distance(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}

func main() {
p := Point{1, 2}
q := Point{4, 6}
fmt.Println(p.Distance(q))  // 5
}

``````type Line struct {
Start  Point
End    Point
// Length float64
// 如果取消上面这行的注释 编译报错：type Line has both field and method named Length
}

func (L Line) Length() float64 {
return L.Start.Distance(L.End)
}

func main() {
p := Point{1, 2}
q := Point{4, 6}
fmt.Println(p.Distance(q))  // 5
line := Line{p, q}
fmt.Println(line.Length())  // 5
}

``````type Path []Point

func (path Path) Distance() float64 {
sum := 0.0
for i := range path {
if i > 0 {
sum += path[i-1].Distance(path[i])
}
}
return sum
}

func main() {
perim := Path{
{1, 1},
{5, 1},
{5, 4},
{1, 1},
}
fmt.Println(perim.Distance())  // 12
}

指针接收者的方法

``````func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}

func main() {
p := Point{1, 2}
p.ScaleBy(200)
fmt.Printf("%+v", p) // {X:200 Y:400}
}

``````type p *int
func (p) f() {/*...*/}  // 编译错误：非法的接收者类型

``````// case1
r := &Point{1, 2}
r.ScaleBy(2)
fmt.Println(*r)  // {2, 4}

// case2
p1 := Point{1, 2}
pptr := &p1
pptr.ScaleBy(2)
fmt.Println(p1)  // {2, 4}

// case3
p2 := Point{1, 2}
(&p2).ScaleBy(2)
fmt.Println(p2)  // {2, 4}

``````Piont{1,2}.ScaleBy(2)  // 编译错误

``````type Point struct{}

func (p *Point) PtrFunc() {}
func (p Point) Func()     {}

func main() {
p := Point{}
ptr := &Point{}
ptr.PtrFunc()
ptr.Func()

Point{}.Func()
Point{}.PtrFunc() // 编译错误：cannot call pointer method on Point literal

p.Func()
p.PtrFunc() // 编译器做了隐式转换
}

nil是一个合法的接收

``````// *IntList的类型nil代表空列表
type IntList struct {
Value int
Next  *IntList
}

func (list *IntList) Sum() int {
if list == nil {
return 0
}
return list.Value + list.Next.Sum()
}

func main() {
a1 := IntList{1, nil}
a2 := IntList{2, &a1}
a3 := IntList{3, &a2}

fmt.Println(a3.Sum())  // 6

}

通过结构体内嵌组成类型

``````import (
"fmt"
"image/color"
"math"
)

type Point struct{ X, Y float64 }

func (p Point) Distance(q Point) float64 {
return math.Hypot(p.X-q.X, p.Y-q.Y)
}

func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}

type ColoredPoint struct {
Point
Color color.RGBA
}

func main() {
var cp ColoredPoint
cp.X = 1
fmt.Println(cp.Point.X)  // 1

p := ColoredPoint{Point{1, 1}, color.RGBA{255, 0, 0, 255}}
q := ColoredPoint{Point{5, 4}, color.RGBA{0, 0, 255, 255}}

//fmt.Println(p.Distance(q)) // 编译错误：cannot use q (type ColoredPoint) as type Point in argument to p.Point.Distance
fmt.Println(p.Distance(q.Point))  // 5
p.ScaleBy(2)
q.ScaleBy(2)
fmt.Println(p.Distance(q.Point))  // 10
}

`ColoredPoint`类型内嵌了`Point`类型，它可以调用`Point``Distance``ScaleBy`方法。也可以直接访问`Point`的成员变量。

``````func (p ColoredPoint) Distance(q Point) float64 {
return p.Point.Distance(q)
}

func (p *ColoredPoint) ScaleBy(factor float64) {
p.Point.ScaleBy(factor)
}

``````import (
"fmt"
"image/color"
"math"
)

type Point struct{ X, Y float64 }

func (p Point) Distance(q Point) float64 {
return math.Hypot(p.X-q.X, p.Y-q.Y)
}

func (p *Point) ScaleBy(factor float64) {
p.X *= factor
p.Y *= factor
}

type ColoredPoint struct {
*Point
Color color.RGBA
}

func main() {
var cp ColoredPoint
cp.Point = &Point{}  // 匿名指针类型的默认值是nil，必须对其进行初始化
cp.Point.X = 1  // 如果没有上面的那一行，执行报错：panic: runtime error: invalid memory address or nil pointer dereference
fmt.Println(cp.Point.X) // 1

p := ColoredPoint{&Point{1, 1}, color.RGBA{255, 0, 0, 255}}  // 初始化是Point传地址
q := ColoredPoint{&Point{5, 4}, color.RGBA{0, 0, 255, 255}}

//fmt.Println(p.Distance(q)) // 编译错误：cannot use q (type ColoredPoint) as type Point in argument to p.Point.Distance
fmt.Println(p.Distance(*q.Point)) // 5  实参传递时，要转化为值
p.ScaleBy(2)
q.ScaleBy(2)
fmt.Println(p.Distance(*q.Point)) // 10
}

``````type ColoredPoint struct {
Point
color.RGBA
}

p := ColoredPoint{Point{1, 1}, color.RGBA{255, 0, 0, 255}}

``````type A struct {}
func (a A) Func() {}
type B struct {}
func (b B) Func() {}
type C struct {
A
B
}

func main() {
c := C{}
c.Func()  // 编译错误：ambiguous selector c.Func
}

*方法只能在命名的类型（比如Point）和指向他们指针（Point）中声明，但内嵌帮助我们能够在未命名的结构体类型中声明方法。

方法变量与表达式

``````a := Point{1, 2}
b := Point{4, 6}
distanceFromA := a.Distance  // 方法变量
fmt.Println(distanceFromA(b))  // 5
origin := Point{0, 0}
fmt.Println(distanceFromA(origin)) // 2.23606797749979

scaleA := a.ScaleBy  // 方法变量
scaleA(2)
fmt.Println(a)  // {2, 4}

``````a := Point{1, 2}
b := Point{4, 6}
distanceFromA := a.Distance  // 方法变量 由a的方法赋予
distance := Point.Distance // 方法表达式 由Point类型的方法赋予

``````fmt.Println(distanceFromA(b))  // 5 方法变量
fmt.Println(distance(a, b))  // 5 方法表达式
fmt.Printf("%T\n", distance) // func(Point, Point) float64

// scale := Point.ScaleBy // 编译报错：nvalid method expression Point.ScaleBy (needs pointer receiver: (*Point).ScaleBy
scale := (*Point).ScaleBy
scale(&a, 2)
fmt.Println(a)
fmt.Printf("%T\n", scale)  // func(*Point, float64)

封装

``````type IntSet struct {
words []uint64
}

type IntSet2 []uint64

封装的优点：

• Go语言封装的单元是包而不是类型，包内的函数和方法对结构体的字段是可见的
• 实现细节可以对包的使用方屏蔽，方便设计者灵活改变
• 防止使用者非法更改结构体内的变量

封装的缺点：

• 需要设计者编写很多的方法来实现对字段的读取和更新，因为调用者无法自助。