go基础6-接口1

接口

接口类型是对于其他类型行为的抽象;因为接口类型通过只声明不定义具体实现细节,来增加函数的灵活性和扩展性;
go中接口类型可以进行隐式实现,即具体实现中不需要定义所有接口声明的函数,只需要按需使用即可.这种定义方式可以让你修改接口时,不用改变已有实现;

接口约定

通过接口约定可以增加函数的灵活性.你不用每次都定义具体的结构和操作集,只通过方法定义即可明确可以通过它实现的功能.不定义具体结构,只是接口的约定的方式可以灵活的实现里氏替换;

func Fprintf(w io.Writer, format string, args ...interface{}) (int, error)
func Printf(format string, args ...interface{}) (int, error) {
    return Fprintf(os.Stdout, format, args...)
}
func Sprintf(format string, args ...interface{}) string {
    var buf bytes.Buffer
    Fprintf(&buf, format, args...)
    return buf.String()
}

// Writer接口定义
package io
type Writer interface {
    Write(p []byte) (n int, err error)
}

因为os.Stdout和&buf满足Writer接口约定,所以可以使用Fprintf函数.

接口类型

接口类型定义了具体的方法集合,而实现方法的具体类型是这个接口类型的实例;

package io
type Reader interface {
    Read(p []byte) (n int, err error)
}

接口还可以通过组合方式进行扩展

type ReadWriter interface {
    Reader
    Writer
}

接口实现

实现:一个类型拥有一个接口所有的方法.这意味着:表达一个类型属于某个接口只要实现该接口即可.

var w io.Writer
w = os.Stdout 

如果具体类型T,它的方法接收器的类型可以是T或*T的指针.在T上调用*T是合法的,因为编译器隐式的获取了它的地址.但这仅仅是一个语法糖,T类型不拥有*T指针的方法.

接口可以封装和隐藏具体实现类型及其值,只有接口中暴露的方法可以被调用到:

os.Stdout.Close() // OK: *os.File has Close method

var w io.Writer
w = os.Stdout
w.Close()  // compile error: io.Writer lacks Close method

空接口类型:interface{}.空接口类型没有实现类型要求,它可以接收任意值,也因此不能直接对它持有值做操作.

go的接口不需要显示定义,在你需要的时候定义一个新的抽象或特定特点的组,而不需要修改具体类型的定义.因为你只要包含该接口的所有方法即意味着实现该接口,所以接口通过隐式实现很灵活.

接口值

接口值:包含了类型和值两部分.它们被称为接口的动态类型和动态值.类型部分代表与之相关类型的描述符.类型描述符指类型的名称和方法.因为go是静态类型语言,类型是编译器的概念,所以一个类型不是一个值.

1 var w io.Writer
2 w = os.Stdout
3 w = new(bytes.Buffer)
4 w = nil

1 定义w变量并初始化.它会会获取接口的零值,type和value都是nil
接口零值

2 将os.File类型的值赋给变量w.赋值过程会进行具体类型到接口类型的隐式转换.它的动态类型被设为os.File指针的类型描述符,它的动态值持有os.Stdout的拷贝;
os.Stdout
因为编译期,我们不知道接口值的动态类型是什么,所以一个接口上的调用必须使用动态分配.实际赋值等价于os.Stdout.Write([]byte("hello")) // "hello"

3 将*bytes.Buffer赋值给变量w.
bytes.Buffer

4 将nil赋值给w.又回到初始化状态.

一个接口值可以持有任意大的动态值.从概念上,不论接口值多大,动态值总能容下它.
接口值可进行==和!=比较.但是由于接口值类型是任意的,如果接口值的动态类型都是不可比较的类型(如切片),比较时会产生panic.
所以进行值比较时,你必须要确定类型可比较,你可以通过fmt.Printf("%T ", w)来查看具体类型.

nil接口值与nil指针接口值:接口值变量初始化值为nil,但是nil指针接口值初始化值不是nil而是类型是变量的指针类型,它的值为nil.这一点常会造成误判,引起程序bug.
nil指针接口值

原文地址:https://www.cnblogs.com/chengmuyu/p/13585720.html