# 10.6. 方法

## 10.6.1 方法是什么

``````func (a *denseMatrix) Add(b Matrix) Matrix
func (a *sparseMatrix) Add(b Matrix) Matrix``````

``func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }``

``func (_ receiver_type) methodName(parameter_list) (return_value_list) { ... }``

`recv` 就像是面向对象语言中的 `this``self`，但是 Go 中并没有这两个关键字。随个人喜好，你可以使用 `this``self` 作为 receiver 的名字。下面是一个结构体上的简单方法的例子：

``````package main

import "fmt"

type TwoInts struct {
a int
b int
}

func main() {
two1 := new(TwoInts)
two1.a = 12
two1.b = 10

fmt.Printf("The sum is: %d\n", two1.AddThem())
fmt.Printf("Add them to the param: %d\n", two1.AddToParam(20))

two2 := TwoInts{3, 4}
fmt.Printf("The sum is: %d\n", two2.AddThem())
}

func (tn *TwoInts) AddThem() int {
return tn.a + tn.b
}

func (tn *TwoInts) AddToParam(param int) int {
return tn.a + tn.b + param
}``````

``````The sum is: 22
Add them to the param: 42
The sum is: 7``````

``````package main

import "fmt"

type IntVector []int

func (v IntVector) Sum() (s int) {
for _, x := range v {
s += x
}
return
}

func main() {
fmt.Println(IntVector{1, 2, 3}.Sum()) // 输出是6
}``````

``````package main

import "container/list"

func (p *list.List) Iter() {
// ...
}

func main() {
lst := new(list.List)
for _= range lst.Iter() {
}
}``````

``cannot define new methods on non-local type int``

``````func (t time.Time) first3Chars() string {
return time.LocalTime().String()[0:3]
}``````

``````package main

import (
"fmt"
"time"
)

type myTime struct {
time.Time //anonymous field
}

func (t myTime) first3Chars() string {
return t.Time.String()[0:3]
}
func main() {
m := myTime{time.Now()}
// 调用匿名Time上的String方法
fmt.Println("Full time now:", m.String())
// 调用myTime.first3Chars
fmt.Println("First 3 chars:", m.first3Chars())
}

/* Output:
Full time now: Mon Oct 24 15:34:54 Romance Daylight Time 2011
First 3 chars: Mon
*/``````

## 10.6.3 指针或值作为接收者

``````package main

import (
"fmt"
)

type B struct {
thing int
}

func (b *B) change() { b.thing = 1 }

func (b B) write() string { return fmt.Sprint(b) }

func main() {
var b1 B // b1是值
b1.change()
fmt.Println(b1.write())

b2 := new(B) // b2是指针
b2.change()
fmt.Println(b2.write())
}

/* 输出：
{1}
{1}
*/``````

``````type Point3 struct { x, y, z float64 }
// A method on Point3
func (p Point3) Abs() float64 {
return math.Sqrt(p.x*p.x + p.y*p.y + p.z*p.z)
}``````

``````package main

import (
"fmt"
)

type List []int

func (l List) Len() int        { return len(l) }
func (l *List) Append(val int) { *l = append(*l, val) }

func main() {
// 值
var lst List
lst.Append(1)
fmt.Printf("%v (len: %d)", lst, lst.Len()) // [1] (len: 1)

// 指针
plst := new(List)
plst.Append(2)
fmt.Printf("%v (len: %d)", plst, plst.Len()) // &[2] (len: 1)
}``````

## 10.6.4 方法和未导出字段

``````package person

type Person struct {
firstName string
lastName  string
}

func (p *Person) FirstName() string {
return p.firstName
}

func (p *Person) SetFirstName(newName string) {
p.firstName = newName
}``````

``````package main

import (
"./person"
"fmt"
)

func main() {
p := new(person.Person)
// p.firstName undefined
// (cannot refer to unexported field or method firstName)
// p.firstName = "Eric"
p.SetFirstName("Eric")
fmt.Println(p.FirstName()) // Output: Eric
}``````

## 10.6.5 内嵌类型的方法和继承

``````type Engine interface {
Start()
Stop()
}

type Car struct {
Engine
}``````

``````func (c *Car) GoToWorkIn() {
// get in car
c.Start()
// drive to work
c.Stop()
// get out of car
}``````

``````package main

import (
"fmt"
"math"
)

type Point struct {
x, y float64
}

func (p *Point) Abs() float64 {
return math.Sqrt(p.x*p.x + p.y*p.y)
}

type NamedPoint struct {
Point
name string
}

func main() {
n := &NamedPoint{Point{3, 4}, "Pythagoras"}
fmt.Println(n.Abs()) // 打印5
}``````

``````func (n *NamedPoint) Abs() float64 {
return n.Point.Abs() * 100.
}``````

## 10.6.6 如何在类型中嵌入功能

A：聚合（或组合）：包含一个所需功能类型的具名字段。

B：内嵌：内嵌（匿名地）所需功能类型，像前一节 10.6.5 所演示的那样。

``````package main

import (
"fmt"
)

type Log struct {
msg string
}

type Customer struct {
Name string
log  *Log
}

func main() {
c := new(Customer)
c.Name = "Barak Obama"
c.log = new(Log)
c.log.msg = "1 - Yes we can!"
// shorter
c = &Customer{"Barak Obama", &Log{"1 - Yes we can!"}}
// fmt.Println(c) &{Barak Obama 1 - Yes we can!}
c.Log().Add("2 - After me the world will be a better place!")
//fmt.Println(c.log)
fmt.Println(c.Log())

}

func (l *Log) Add(s string) {
l.msg += "\n" + s
}

func (l *Log) String() string {
return l.msg
}

func (c *Customer) Log() *Log {
return c.log
}``````

``````1 - Yes we can!
2 - After me the world will be a better place!``````

``````package main

import (
"fmt"
)

type Log struct {
msg string
}

type Customer struct {
Name string
Log
}

func main() {
c := &Customer{"Barak Obama", Log{"1 - Yes we can!"}}
c.Add("2 - After me the world will be a better place!")
fmt.Println(c)

}

func (l *Log) Add(s string) {
l.msg += "\n" + s
}

func (l *Log) String() string {
return l.msg
}

func (c *Customer) String() string {
return c.Name + "\nLog:" + fmt.Sprintln(c.Log)
}``````

``````Barak Obama
Log:{1 - Yes we can!
2 - After me the world will be a better place!}``````

## 10.6.7 多重继承

``````package main

import (
"fmt"
)

type Camera struct{}

func (c *Camera) TakeAPicture() string {
return "Click"
}

type Phone struct{}

func (p *Phone) Call() string {
return "Ring Ring"
}

type CameraPhone struct {
Camera
Phone
}

func main() {
cp := new(CameraPhone)
fmt.Println("Our new CameraPhone exhibits multiple behaviors...")
fmt.Println("It exhibits behavior of a Camera: ", cp.TakeAPicture())
fmt.Println("It works like a Phone too: ", cp.Call())
}``````

``````Our new CameraPhone exhibits multiple behaviors...
It exhibits behavior of a Camera: Click
It works like a Phone too: Ring Ring``````

`point.go` 开始（第 10.1 节的练习）：使用方法来实现 `Abs()``Scale()`函数，`Point` 作为方法的接收者类型。也为 `Point3``Polar` 实现 `Abs()` 方法。完成了 `point.go` 中同样的事情，只是这次通过方法。

``````package main

import (
"fmt"
)

type Base struct{}

func (Base) Magic() {
fmt.Println("base magic")
}

func (self Base) MoreMagic() {
self.Magic()
self.Magic()
}

type Voodoo struct {
Base
}

func (Voodoo) Magic() {
fmt.Println("voodoo magic")
}

func main() {
v := new(Voodoo)
v.Magic()
v.MoreMagic()
}``````

## 10.6.9 和其他面向对象语言比较 Go 的类型和方法

Go 不需要一个显式的类定义，如同 Java、C++、C# 等那样，相反地，“类”是通过提供一组作用于一个共同类型的方法集来隐式定义的。类型可以是结构体或者任何用户自定义类型。

``````type Integer int
func (i *Integer) String() string {
return strconv.Itoa(int(*i))
}``````

a）假设定义： `type Integer int`，完成 `get()` 方法的方法体: `func (p Integer) get() int { ... }`

b）定义： `func f(i int) {}; var v Integer` ，如何就 v 作为参数调用f？

c）假设 `Integer` 定义为 `type Integer struct {n int}`，完成 `get()` 方法的方法体：`func (p Integer) get() int { ... }`

d）对于新定义的 `Integer`，和 b）中同样的问题。

0 个点赞 | 1 个回复 | 问答