0
点赞
收藏
分享

微信扫一扫

go接口理解


一:接口的定义

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()
}

  1. 接口中的所有方法都没有结构体;
  2. 一个自定义类型需要将接口的所有方法都实现,我们就会说该自定义类型实现了该接口;
  3. 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例赋给接口(与③结合起来);
  4. 只要是自定义类型就可以实现接口,而不单单是结构体。

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 ]

  1. 一个自定义类型可以实现多个接口

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

  1. 接口中不能有任何变量
  2. 接口也可以继承,只不过需要把所有继承的方法都要实现(包括本身的方法)
  3. 空接口interface{}可以接受任何数据类型.

func main() {
var testinterface{}
test = 10
fmt.Println(test)
test ="louis"
fmt.Println(test)
}
结果
[ `go runinterface.go` | done ]
10

  1. 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


举报

相关推荐

0 条评论