一:接口的定义
interface类型可以定义一组方法,但这些方法不需要实现。且interface不能包含任何字段,某个自定义类型(如结构体),需要用到时再具体实现该方法。
type 接口名 interface{
method1(参数列表) 返回值列表
method2(参数列表) 返回值列表
}
func(t 自定义类型)method1(参数列表,返回值列表){
//方法实现
}
func(t 自定义类型)method2(参数列表,返回值列表){
//方法实现
}
二:简单使用举例
type itfinterface{
SayHello()
Plud(num1 int, num2 int) int
}
type Personalstruct{
}
func (p Personal) SayHello() {
fmt.Println("hello world!")
}
func (p Personal) Plud(num1 int, num2 int) int{
return num1 + num2
}
func main() {
var p Personal
p.SayHello()
res := p.Plud(1, 2)
fmt.Println(res)
}
结果
[ `go runinterface.go` | done ]
hello world!
3
三:接口使用细节
1.接口本身不可以创建示例,但可以指向一个实现该接口方法的自定义的类型(如结构体)
func main() {
var p Personal
var pp Itf = p
pp.SayHello()
}
- 接口中的所有方法都没有结构体;
- 一个自定义类型需要将接口的所有方法都实现,我们就会说该自定义类型实现了该接口;
- 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例赋给接口(与③结合起来);
- 只要是自定义类型就可以实现接口,而不单单是结构体。
package main
import (
"fmt"
)
type Itf interface{
Say()
}
type inter int
func (i inter) Say() {
fmt.Printf("这是数字%v",i)
}
func main() {
var i inter = 1
var ii Itf = i
ii.Say()
}
结果
[ `go runinterface.go` | done ]
- 一个自定义类型可以实现多个接口
package main
import (
"fmt"
)
type A interface{
Say()
}
type B interface{
Plud()
}
type C struct{
}
func (a C) Say() {
fmt.Println("hello world!")
}
func (b C) Plud() {
fmt.Println(1+1)
}
func main() {
var c C
var a A = c
a.Say()
var b B = c
b.Plud()
}
结果
[ `go runinterface.go` | done ]
hello world!
2
- 接口中不能有任何变量
- 接口也可以继承,只不过需要把所有继承的方法都要实现(包括本身的方法)
- 空接口interface{}可以接受任何数据类型.
func main() {
var testinterface{}
test = 10
fmt.Println(test)
test ="louis"
fmt.Println(test)
}
结果
[ `go runinterface.go` | done ]
10
- interface默认为指针类型。
备注:如果要调用接口方法,则接口里的方法必须全部实现,无论该方法是否会被使用,否则报错。
四.全部实现所有接口方法,如果不实现所有接口方法,意味着没有继承这个接口
1. 示例1
package main
import (
"fmt"
)
type Phone interface {
call()
start()
}
type NokiaPhone struct {
}
func (nokiaPhone NokiaPhone) call() {
fmt.Println("I am Nokia, I can call you!")
}
func (nokiaPhone NokiaPhone) start() {
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
}
func (iPhone IPhone) call() {
fmt.Println("I am iPhone, I can call you!")
}
func (iPhone IPhone) start() {
fmt.Println("I am iPhone, I can start you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
2. 示例2
Go接口可以作为结构上的方法实现。 考虑以下接口:
type Shape interface {
GetPerimeter() int
GetArea() int
}
以下是Shape接口的两个具体实现:
type Square struct {
side uint
}
func (s *Square) GetPerimeter() uint {
return s.side * 4
}
func (s *Square) GetArea() uint {
return s.side * s.side
}
type Rectangle struct {
width uint
height uint
}
func (r *Rectangle) GetPerimeter() uint {
return (r.width + r.height) * 2
}
func (r *Rectangle) GetArea() uint {
return r.width * r.height
}
计算Square和Rectangle的总面积
main() {
shapes := []Shape{&Square{side: 2},
&Rectangle{width: 3, height: 5}}
var totalArea uint
for _, shape := range shapes {
totalArea += shape.GetArea()
}
fmt.Println("Total area: ", totalArea)
3. 示例3,组合优于继承
在许多编程语言中,都有一个基类的概念,该基类可用于实现所有子类使用的共享功能。 Go(正确地)更喜欢组合而不是继承。
以下是go语言组合优于继承的实例
type Cache struct {
cache map[string]uint
}
func (c *Cache) GetValue(name string) int {
value, ok := c.cache[name]
if ok {
fmt.Println("cache hit")
return int(value)
} else {
fmt.Println("cache miss")
return -1
}
}
func (c *Cache) SetValue(name string, value uint) {
c.cache[name] = value
}
现在,我将此缓存嵌入到Square和Rectangle形状中。 请注意, GetPerimeter()和GetArea()现在会首先检查缓存,并仅在缓存中没有该值时才计算该值。
type Square struct {
Cache
side uint
}
func (s *Square) GetPerimeter() uint {
value := s.GetValue("perimeter")
if value == -1 {
value = int(s.side * 4)
s.SetValue("perimeter", uint(value))
}
return uint(value)
}
func (s *Square) GetArea() uint {
value := s.GetValue("area")
if value == -1 {
value = int(s.side * s.side)
s.SetValue("area", uint(value))
}
return uint(value)
}
type Rectangle struct {
Cache
width uint
height uint
}
func (r *Rectangle) GetPerimeter() uint {
value := r.GetValue("perimeter")
if value == -1 {
value = int(r.width + r.height) * 2
r.SetValue("perimeter", uint(value))
}
return uint(value)
}
func (r *Rectangle) GetArea() uint {
value := r.GetValue("area")
if value == -1 {
value = int(r.width * r.height)
r.SetValue("area", uint(value))
}
return uint(value)
}
最后, main()函数两次计算总面积以查看缓存效果。
func main() {
shapes := []Shape{
&Square{Cache{cache: make(map[string]uint)}, 2},
&Rectangle{Cache{cache: make(map[string]uint)}, 3, 5}
}
var totalArea uint
for _, shape := range shapes {
totalArea += shape.GetArea()
}
fmt.Println("Total area: ", totalArea)
totalArea = 0
for _, shape := range shapes {
totalArea += shape.GetArea()
}
fmt.Println("Total area: ", totalArea)
这是输出:
cache miss
cache miss
Total area: 19
cache hit
cache hit
Total area: 19