go接口详解

栏目: IT技术 · 发布时间: 5年前

内容简介:go面向接口编程知识点接口(interface)是一种类型,用来定义行为(方法)。这句话有两个重点,首先解释定义行为:

go面向接口编程知识点

接口定义与格式

接口(interface)是一种类型,用来定义行为(方法)。这句话有两个重点, 类型定义行为

首先解释定义行为:

接口即一组方法定义的集合,定义了对象的一组行为,就是定义了一些函数,由具体的类型实例实现具体的方法。

换句话说,一个接口就是定义(规范或约束),接口并不会实现这些方法,具体的实现由类实现,实现接口的类必须严格按照接口的声明来实现接口提供的所有功能。接口的作用应该是将定义与实现分离,降低耦合度。

在多人合作开发同一个项目时,​接口表示调用者和设计者的一种约定,事先定义好相互调用的接口可以大大提高开发的效率。有了接口,就可以在不影响现有接口声明的情况下,修改接口的内部实现,从而使兼容性问题最小化。

接口的定义格式:

type Namer interface {
    Method1(param_list) return_type  //方法名(参数列表) 返回值列表
    Method2(param_list) return_type  //方法名(参数列表) 返回值列表
   ......
}

隐式实现及实现条件

怎么实现接口:

实现接口的类并不需要显式声明,只需要实现接口所有的函数就表示实现了该接口,而且类还可以拥有自己的方法。

接口能被哪些类型实现:

接口可以被结构体实现,也可以被函数类型实现。

接口被实现的条件:

接口被实现的条件一:接口的方法与实现接口的类型方法格式一致(方法名、参数类型、返回值类型一致)。

接口被实现的条件二:接口中所有方法均被实现。

package main
 
import "fmt"
 
type Shaper interface {
    Area() float64
    //  Perimeter() float64
}
 
type Rectangle struct {
    length float64
    width  float64
}
 
// 实现 Shaper 接口中的方法
func (r *Rectangle) Area() float64 {
    return r.length * r.width
}
 
// Set 是属于 Rectangle 自己的方法
func (r *Rectangle) Set(l float64, w float64) {
    r.length = l
    r.width = w
}
 
func main() {
    rect := new(Rectangle) //创建指针类型的结构体实例(类实例)
    rect.Set(2, 3)
    areaIntf := Shaper(rect) //这里将指针类型实例赋值给接口,下面会介绍。
    fmt.Printf("The rect has area: %f\n", areaIntf.Area())
}

接口赋值

现在来解释接口是一个类型,本质是一个指针类型,那么什么样的值可以赋值给接口,有两种: 实现了该接口的类 或者 接口

1.将对象赋值给接口

当接口实例中保存了自定义类型的实例后,就可以直接从接口上调用它所保存的实例的方法。

package main

import (
	"fmt"
)

//定义接口
type Testinterface interface{
	Teststring() string
	Testint() int
}

//定义结构体
type TestMethod struct{
	name string
	age int
}

//结构体的两个方法隐式实现接口
func (t *TestMethod)Teststring() string{
	return t.name
}

func (t *TestMethod)Testint() int{
	return t.age
}

func main(){
	T1 := &TestMethod{"ling",34}
	T2 := TestMethod{"gos",43}
	//接口本质是一种类型
	//接口赋值:只要类实现了该接口的所有方法,即可将该类赋值给这个接口
	var Test1 Testinterface  //接口只能是值类型
	Test1 = T1   //TestMethod类的指针类型实例传给接口
	fmt.Println(Test1.Teststring())
	fmt.Println(Test1.Testint())

	Test2 := T2   //TestMethod类的值类型实例传给接口
	fmt.Println(Test2.Teststring())
	fmt.Println(Test2.Testint())
}

2.将接口赋值给另一个接口

1.只要两个接口拥有相同的方法列表(与次序无关),即是两个相同的接口,可以相互赋值

2.接口赋值只需要接口A的方法列表是接口B的子集(即假设接口A中定义的所有方法,都在接口B中有定义),那么B接口的实例可以赋值给A的对象。反之不成立,即子接口B包含了父接口A,因此可以将子接口的实例赋值给父接口。

3.即子接口实例实现了子接口的所有方法,而父接口的方法列表是子接口的子集,则子接口实例自然实现了父接口的所有方法,因此可以将子接口实例赋值给父接口。

3.接口类型作为参数

第一点已经说了可以将实现接口的类赋值给接口,而将接口类型作为参数很常见。这时,那些实现接口的实例都能作为接口类型参数传递给函数/方法。

package main
import (
	"fmt"
)
//Shaper接口
type Shaper interface {
	Area() float64
}
// Circle struct结构体
type Circle struct {
	radius float64
}
// Circle类型实现Shaper中的方法Area()
func (c *Circle) Area() float64 {
	return 3.14 * c.radius * c.radius
}

func main() {
	// Circle的指针类型实例
	c1 := new(Circle)
	c1.radius = 2.5
	//将 Circle的指针类型实例c1传给函数myArea,接收类型为Shaper接口
	myArea(c1)
}
func myArea(n Shaper) {
	fmt.Println(n.Area())
}

空接口是指没有定义任何接口方法的接口。 没有定义任何接口方法,意味着 Go 中的任意对象都已经实现空接口(因为没方法需要实现),只要实现接口的对象都可以被接口保存,所以任意对象都可以保存到空接口实例变量中

空接口的定义方式:

type empty_int interface {}

更常见的,会直接使用 interface{} 作为一种类型,表示空接口。例如:

// 声明一个空接口实例
var i interface{}

再比如函数使用空接口类型参数:

func myfunc(i interface{})

如何使用空接口

可以定义一个空接口类型的array、slice、map、struct等,这样它们就可以用来存放任意类型的对象,因为任意类型都实现了空接口。

package main

import "fmt"

func main() {
    any := make([]interface{}, 5)
    any[0] = 11
    any[1] = "hello world"
    any[2] = []int{11, 22, 33, 44}
    for _, value := range any {
        fmt.Println(value)
    }
}
11
hello world
[11 22 33 44]
<nil>
<nil>

通过空接口类型,Go也能像其它动态语言一样,在数据结构中存储任意类型的数据。

接口嵌套

接口可以嵌套,嵌套的内部接口将属于外部接口,内部接口的方法也将属于外部接口。

另外在类型嵌套时,如果内部类型实现了接口,那么外部类型也会自动实现接口,因为内部属性是属于外部属性的。

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}
 
type Lock interface {
    Lock()
    Unlock()
}
 
type File interface {
  //ReadWrite为内部接口
    ReadWrite
  //Lock为内部接口
    Lock
    Close()
}

类型断言

类型断言为判断一个类型有没有实现接口。

假如我现在写了一个结构体类型 MyFile 来实现上面的  File 接口,那么我如何知道  MyFile 是否实现了  File 接口呢?

package main
 
import "fmt"
 
type MyFile struct{}
 
func (m *MyFile) Read() bool {
    fmt.Printf("Read()\n")
    return true
}
 
// ...
// 假设我这里相继实现了 Write(), Lock(),Unlock() 和 Close() 方法
 
func main() {
    my := new(MyFile)
    fIntf := File(my)
 
    // 看这里,看这里
    if v, ok := fIntf.(*MyFile); ok {
        v.Read()
    }
}  

类型断言的格式:

if v, ok : = varI.(T) ; ok { 
   // checked type assertion
     //do something
    return
}

如果 v 是  varI 转换到类型  T 的值, ok 会是  true ;否则  v 是类型  T 的零值, ok 是  false

要是多个类型实现了同一个接口,比如前面的 areaIntf ,要如何测试呢? 

那就要用  type-switch 来判断了。

switch t := areaIntf.(type) {
case *Rectangle:
    // do something
case *Triangle:
    // do something
default:
    // do something
}

1、多个类型(结构体)可以实现同一个接口。

2、一个类型(结构体)可以实现多个接口。

3、实现接口的类(结构体)可以赋值给接口。

package main

import "fmt"

type Shaper interface {
	Area() float64
}

// ==== Rectangle ====
type Rectangle struct {
	length float64
	width  float64
}

// 实现 Shaper 接口中的方法
func (r *Rectangle) Area() float64 {
	return r.length * r.width
}

// Set 是属于 Rectangle 自己的方法
func (r *Rectangle) Set(l float64, w float64) {
	r.length = l
	r.width = w
}


// ==== Triangle ====
type Triangle struct {
	bottom float64
	hight  float64
}

func (t *Triangle) Area() float64 {
	return t.bottom * t.hight / 2
}

func (t *Triangle) Set(b float64, h float64) {
	t.bottom = b
	t.hight = h
}

// ==== Triangle End ====

func main() {
	rect := new(Rectangle)
	rect.Set(2, 3)
	areaIntf := Shaper(rect) //这种方法只能将指针类型的类示例赋值给接口
	fmt.Printf("The rect has area: %f\n", areaIntf.Area())

	triangle := new(Triangle)
	triangle.Set(2, 3)
	areaIntf = Shaper(triangle) //这种方法只能将指针类型的类示例赋值给接口
	fmt.Printf("The triangle has area: %f\n", areaIntf.Area())
}


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Information

The Information

James Gleick / Vintage / 2012-3-6 / USD 16.95

James Gleick, the author of the best sellers Chaos and Genius, now brings us a work just as astonishing and masterly: a revelatory chronicle and meditation that shows how information has become th......一起来看看 《The Information》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具