方法和接口
方法
Go語言中沒有類吱抚,但是可以在結(jié)構(gòu)類型上定義方法逝钥,實(shí)際上可以對(duì)包中的任意類型定義任意方法,但是不能對(duì)來自其他包的類型或基礎(chǔ)數(shù)據(jù)類型來定義方法
方法的接收者
方法的接收者可以是指針類型,也可以是值類型
為什么要使用指針作為方法的接收者俏竞?
- 避免在每個(gè)方法調(diào)用中拷貝值
- 方法可以修改接收者指向的值
兩種實(shí)現(xiàn)方式的對(duì)比
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}
v.Scale(5)
fmt.Println(v, v.Abs()) // &{15 20} 25
}
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}
v.Scale(5)
fmt.Println(v, v.Abs()) // &{3 4} 5
}
對(duì)比傳值和傳地址的結(jié)果出皇,可以發(fā)現(xiàn)傳值的方式讀入的v是v的副本羞芍,因而無法修改原始值,經(jīng)過scale之后v的原始值并沒有發(fā)生變化
接口
接口類型是由一組方法構(gòu)成的集合郊艘,任何實(shí)現(xiàn)了接口中所有的方法的值都可以用接口的值來接收
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
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 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
func main() {
var a Abser
f := MyFloat(math.Sqrt2)
v := Vertex{3, 4}
a = f
fmt.Println(a.Abs())
a = &v
fmt.Println(a.Abs())
}
接口的實(shí)現(xiàn)是隱式的荷科,隱式接口解耦了實(shí)現(xiàn)接口的包和定義接口的包唯咬,互不依賴
空接口
interface{}
空接口是指不包含任何方法的接口,空接口可以接收任何類型畏浆。常用來處理類型未知的值
空接口結(jié)合switch進(jìn)行類型匹配
package main
import (
"fmt"
)
func identifyType(i interface{}) {
switch v := i.(type) {
case int:
fmt.Println("An int:", v)
case float64:
fmt.Println("A float64:", v)
case string:
fmt.Println("A string:", v, "length =", len(v))
case bool:
fmt.Println("A bool:", v)
case rune:
fmt.Println("A rune:", string(v))
default:
fmt.Printf("Unknown type: %T(%v)\n", v, v)
}
}
type Vertex struct {
X, Y float64
}
var pt Vertex = Vertex{1, 2}
var i interface{} = map[int]string{1: "hello", 2: "bye"}
func main() {
identifyType(1200)
identifyType(12.21)
identifyType("hello")
identifyType(true)
identifyType('p')
identifyType(func()int{return 1})
identifyType([]int{1, 2, 3})
identifyType(map[string]int{"hello": 100, "world": 200})
identifyType(pt)
identifyType(i)
}