package main import ( "fmt" "io" "os" ) func main() { // dog := Dog{Name: "旺财"} fmt.Println(dog.Speak()) // cat := Cat{Name: "招财猫"} fmt.Println(cat.Speak()) // cow := Cow{Name: "小牛"} fmt.Println(cow.Speak()) // 必须知道对象的对象, 才能调用, 面向具体类型来编写代码, 依赖具体类型, 耦合度高 // 没有一层统一抽象,上层业务逻辑,需要知道对象,才能调用,非常麻烦,高耦合 // speakers := []interface{}{dog, cat, cow} // speakers := []any{dog, cat, cow} // for _, speaker := range speakers { // switch speaker.(type) { // case Dog: // fmt.Println(speaker.(Dog).Speak()) // case Cat: // fmt.Println(speaker.(Cat).Speak()) // case Cow: // fmt.Println(speaker.(Cow).Speak()) // case Person: // fmt.Println(speaker.(Person).Speak()) // } // //... // } person := Person{Name: "小明"} // 管理员,组织这些演技者,进行演讲 // interface 先制定规范, 底层系统按照规范进行实现,上层业务代码的编写将会是透明的,简单高效 // 这里的Speaker 和 Dog Cat Cow 都是type 他们是一种东西吗? // speakers = []Dog{}{dog1,dog2, dog3} // Speaker 是一种约束, 约束放入这个slice里面的对象,必须实现这个接口的所有方法 speakers := []Speaker{dog, cat, cow, person} for _, speaker := range speakers { fmt.Println(speaker.Speak()) // 类型断言, 判断这个speaker是否是Dog类型, 如果是就调用Dog的GetName方法 // 断言成一个具体的类型来使用,一般不建议,因为这样就失去了接口的意义,接口的意义就是不关心具体类型,只关心方法 // if dog, ok := speaker.(Dog); ok { // fmt.Println(dog.GetName()) // } // 不安全方式(会panic) // dog := a.(Dog) // 如果a不是Dog类型,会panic // speaker.(Dog).GetName() // 只能调用接口的方法, 不能调用具体类型的方法 } // 只关注 方法(接口), 不关注 对象的编程的方式,就是面向接口 // 1. 使用固定1k缓冲区循环读取文件并输出 buf := NewBuffer() f, err := os.Open("main.go") if err != nil { panic(err) } defer f.Close() // 循环读取:文件 -> 缓冲区 -> 标准输出 for { // 清空缓冲区准备接收新数据 buf.Reset() // 从文件读取最多1k数据到缓冲区 n, err := io.CopyN(buf, f, 1024) if n > 0 { // 将缓冲区的数据输出到标准输出 fmt.Printf("\n--- 读取了 %d 字节 ---\n", n) io.Copy(os.Stdout, buf) } if err == io.EOF { break } if err != nil { panic(err) } } } // 任何一个结构体 实现了这个接口的所有方法, 就实现了这个接口 // 接口是一层抽象, 只要实现了这个接口的所有方法, 就可以被当做这个接口来使用,屏蔽了底层系统 type Speaker interface { Speak() string // 说话方法 GetName() string // 获取名字方法 } // 2. 定义不同的类型 type Dog struct { Name string } // 3. 实现接口方法 func (d Dog) Speak() string { return "汪汪汪" } func (d Dog) GetName() string { return d.Name } type Cat struct { Name string } func (c Cat) Speak() string { return "喵喵喵" } func (c Cat) GetName() string { return c.Name } type Cow struct { Name string } func (c Cow) Speak() string { return "哞哞哞" } func (c Cow) GetName() string { return c.Name } // 标注自己实现了Speaker 不需要 type Person struct { Name string } func (p Person) Speak() string { return "hello" } func (p Person) GetName() string { return p.Name } func NewBuffer() *Buffer { return &Buffer{ // 固定 1k 大小的缓冲区 buf: make([]byte, 1024), dataLen: 0, } } // 实现 Reader和 Writer方法 type Buffer struct { buf []byte // 固定大小的缓冲区 dataLen int // 当前缓冲区中的数据量 } func (b *Buffer) Read(p []byte) (n int, err error) { if b.dataLen == 0 { return 0, io.EOF } // 读取缓冲区中的数据 n = copy(p, b.buf[:b.dataLen]) fmt.Println("read: ", n) // 移除已读数据(将未读数据前移) copy(b.buf, b.buf[n:b.dataLen]) b.dataLen -= n return n, nil } func (b *Buffer) Write(p []byte) (n int, err error) { // 计算剩余空间 available := len(b.buf) - b.dataLen if available == 0 { // 缓冲区已满 return 0, io.ErrShortBuffer } // 只写入缓冲区能容纳的数据(固定大小,不扩展) n = copy(b.buf[b.dataLen:], p) b.dataLen += n fmt.Printf("write: %d 字节, 缓冲区使用: %d/%d\n", n, b.dataLen, len(b.buf)) // 如果没能写入全部数据,返回 ErrShortBuffer if n < len(p) { return n, io.ErrShortBuffer } return n, nil } func (b *Buffer) String() string { return string(b.buf[:b.dataLen]) } // Reset 清空缓冲区 func (b *Buffer) Reset() { b.dataLen = 0 } // end