接口
Go 接口是隐式实现。 对于一个数据类型,无需声明它实现了哪些接口,只需要实现接口必需的方法即可。当然了,存在一个小问题就是: 我们可能无意间实现了某个接口:) ,所以 命名
是多么重要的一件事情。
语法规则
type 接口名称 interface {
方法1名称(参数列表 ...) 返回值列表...
方法2名称(参数列表 ...) 返回值列表...
方法3名称(参数列表 ...) 返回值列表...
...
...
}
例子
求矩形和圆的周长, 面积
package main
import (
"fmt"
"math"
)
// 声明一个图形接口
type geometry interface {
area() float64
perimeter() float64
}
// 多个字段类型相同时,可以并列声明
type rectangle struct {
width, height float64
}
type circle struct {
radius float64
}
// rectangle 隐式实现了 geometry 接口的 area 方法
func (r *rectangle) area() float64 {
return r.width * r.height
}
// rectangle 隐式实现了 geometry 接口的 perimeter 方法
func (r *rectangle) perimeter() float64 {
return (r.width + r.height) * 2
}
// circle 隐式实现了 geometry 接口的 area 方法
func (c *circle) area() float64 {
return math.Pi * c.radius * c.radius
}
// circle 隐式实现了 geometry 接口的 perimeter 方法
func (c *circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}
func main() {
r := &rectangle{
width: 10,
height: 5,
}
fmt.Printf("Rectangle area = %.2f, perimeter = %.2f \n", r.area(), r.perimeter())
c := &circle{
radius: 10,
}
fmt.Printf("Circle area = %.2f, perimeter = %.2f \n", c.area(), c.perimeter())
}
// $ go run main.go
// 输出如下
/**
Rectangle area = 50.00, perimeter = 30.00
Circle area = 314.16, perimeter = 62.83
*/
方法
方法的声明和普通函数的声明类似,只是在函数名字前面多了一个 接收者参数
(接收者参数将方法绑定到其对应的数据类型上)。方法可以绑定到任何数据类型上,但是大多数情况下,绑定的都是 结构体。
语法规则
func (接收者参数) 方法名称(参数列表 ...) 返回值列表... {
// do something
}
例子
结构体方法
package main
import "fmt"
type person struct {
name string
age int16
}
func (p person) sayName() {
fmt.Printf("Hi, my name is %s\n", p.name)
}
func (p person) sayAge() {
fmt.Printf("Hi, my age is %d\n", p.age)
}
func main() {
tom := &person{
name: "Tom",
age: 6,
}
tom.sayName()
tom.sayAge()
}
// $ go run main.go
// 输出如下
/**
Hi, my name is Tom
Hi, my age is 6
*/
结构体指针方法
相比结构体方法,指针结构体方法除了将方法参数变为指针外,在引用对应的字段时,无需加 *
标识符, 这一点和普通指针变量引用时有所区别,需要注意。
package main
import "fmt"
type person struct {
name string
age int16
}
func (p *person) sayName() { // 结构体为指针类型
fmt.Printf("Hi, my name is %s\n", p.name)
}
func (p *person) sayAge() { // 结构体为指针类型
fmt.Printf("Hi, my age is %d\n", p.age)
}
func main() {
tom := &person{
name: "Tom",
age: 6,
}
tom.sayName()
tom.sayAge()
}
// $ go run main.go
// 输出如下
/**
Hi, my name is Tom
Hi, my age is 6
*/
编译检测
编译器会对方法的 接收者参数
进行检查,具体来说:
• 接收者形参为普通变量类型
• 实参为普通变量类型,编译正常
• 实参为指针变量类型,编译正常
• 接收者形参为指针变量类型
• **实参为普通变量类型,编译报错**
• 实参为指针变量类型,编译正常