5 面向对象

1 类型系统

1.1给类型添加方法

// 为类型添加方法
type Integer int  // 定义一个新类型Integer, 它与int类型相同

func (a Integer) Less(b Integer) bool {    // 给Integer类型添加新方法 less, less 方法输入一个整数,返回布尔值
    return a < b  // 当前整数a调用less方法要传入一个整数b, 如果a<b,返回true
}

如果我们想在方法中修改对象,这种时候必须就要用到指针

func (a *Integer) Add (b Integer) {
    *a += b
}

func main()  {
    a := Integer(10)
    a.Add(5)
    fmt.Println("a is : ", a)
}

 1.2 值语义和引用语义

b = a
b.Modyfy()
// 如果a的值收到影响则a为引用类型,否则为值类型

值类型的数据:

  • 基本数据类型
  • 符合类型: 数组, 结构体, 指针
// 数组想表达引用
var a = [3]int{1,2,3}
var b = &a
b[1]++
fmt.Println(a, *b)

类似引用类型的数据:

  1. 数组切片 : 指向数组的一个区间
  2. map : 键值对
  3. channel : 执行体间的通信设施
  4. 接口 : 对一组满足某个契约的类型的抽象

1.3 结构体

定义矩阵类型

type Rect struct {。      // 定义矩形类型
    x, y float64
    width, height float64
}

func (r *Rect) Area() float64{    //定义成员方法计算矩形面积
    return r.width * r.height
}

2. 初始化

初始化Rect类型的实例

rect1 := new(Rect)
rect2 := &Rect{}
rect3 := &Rect{0, 0, 100, 200}
rect4 := {100, height:200}

3 匿名组合

type Base struct {   // 定义Base类
    Name string
}

func (base *Base) Par() {   // Base类实现Par方法和Run方法
    fmt.Println("par in Base")
}

func (base *Base) Run() {    
    fmt.Println("run in base")
}

type Foo struct {      // Foo类继承Base类
    Base
}

func (foo *Foo) Run() {    // Foo类重写Run方法,先执行Base的Run方法在执行自己的代码
    foo.Base.Run()
    fmt.Println("run in foo")
}

func main()  {
    foo := new(Foo)  // 实例化一个foo对象,该对象有继承自父类的Par方法和自己的Run方法
    foo.Par()
    foo.Run()
}

 4.接口

4.1 非侵入式接口

go语言中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口

例如:

type File  struct{

}

func (f *File) Read (buf []byte) (n int, err error){
    return
}

func (f *File) Write(buf []byte) (n int, err error) {
    return
}

func (f *File) Seek (buf []byte) (n int, err error) {
    return
}

func (f *File) Close () (e error) {
    return
}

type IFile interface {
    Read(buf []byte)(n int, err error)
}

type IReader interface {
    Read(buf []byte)(n int, err error)
    Write(buf []byte)(n int, err error)
    Close(buf []byte)(n int, err error)
}

func main()  {
    var file1 IFile = new(File)
    fmt.Println(file1)
}

我们定义了一个File类,并实现了Read, Write, Seek, Close等方法。我们有IFile,IReader接口,尽管File类没有从这些接口继承,甚至不知道这些接口的存在,但是File类实现了这些接口,可以进行赋值

4.2 接口赋值

接口赋值的两种情况:

  1. 将对象赋值给接口

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

type Integer1 int

func (a Integer1)Less(b Integer1) bool {
    return a < b
}

func (a *Integer1)Add(b Integer1)  {
    *a += b
}

type Lessadd interface {
    Less(b Integer1) bool
    Add(b Integer1)
}

type Less interface {
    Less(b Integer1) bool
}

func main()  {
    int1 := Integer1(5)
  // 将对象赋值给接口
var ld Lessadd = &int1 //注意这两种情形的区别,因为Integer1类Add方法中我们要改变自身需要传递指针,所以在给接口赋值时也要传递指针。否则编译不通过 var ll Less = int1 // 这里不需要传递指针 fmt.Println(int1, ld.Less(6), ll) }

 在go语言中,只要两个接口拥有相同的方法列表,次序不同不要紧,那么他们就是等同的,可以相互赋值

package one

type ReaderWriter interface {
    Read(buf []byte) (n int, err error)
    Write(buf []byte) (n int, err error)
}
package two

type IStream interface{
    Write(buf []byte)(n int, err error)
    Read(buf []byte)(n int, err error)
}

两个包中分别有两个接口,这两个接口有同样的方法列表,只是次序不同,他们可以相互赋值

func main()  {
    var f1 two.IStream = new(File)
    var f2 one.ReaderWriter = f1
    var f3 two.IStream = f2
    fmt.Println(f1, f2, f3)
}

接口赋值并不要求两个接口完全的等价,只要A的方法列表B包含在的方法列表中,那么B的对象即可赋值给A接口

package main

import "fmt"

type Animal interface{
    Speaking() string
}

type Cat struct{}

func (c *Cat) Speaking()string  {
    return "喵喵喵"
}

type Sheep struct {}

func (s Sheep)Speaking()string  {
    return "咩咩咩"
}

type Zhangbin struct {}

func (z Zhangbin)Speaking()string  {
    return "汪汪汪"
}



func main()  {
        var animals = []Animal{&Cat{}, Sheep{}, Zhangbin{}}    // 注意这里必须使用指针来实例化cat对象,因为cat的指针有speaking方法,而cat对象本身不具备speaking方法
        fmt.Println(animals)
    }

4.3 接口查询

type Writer interface {
    Write(buf []byte)(n int, err error)
}

func main()  {
    var f1 two.IStream = new(File)
    var f2 one.ReaderWriter = f1
    var f3 two.IStream = f2

    var f4 Writer = f1   // IStream实现了Write方法,所以可以赋值给Writer
    //var f5 two.IStream = f4  // 因为Writer没有实现Read方法,所以不能赋值给IStream


    fmt.Println(f1, f2, f3, f4, f5)
}
var file1 Writer = ...
if file5, ok := file1.(two.IStream);ok {
    ...  
}


// if语句查询file1接口指向的对象实例是否实现了two.IStream接口
type File struct {}    // 创建File类, 这个类实现了 Write, Read, Close方法

func (f *File)Write()  {
    return
}

func (f *File)Read()  {
    return
}

func (f *File)Close()  {
    return
}

type WR interface{           // WR接口
    Write()
    Read()
}

type W interface {            // W接口
    Write()
}

func main()  {
        var wr1 W = new(File)
        _, ok := wr1.(WR)            // 查看wr1指向的对象是否实现了了WR接口
        fmt.Println(wr1, ok)
    }

查询接口所指向的对象实例是否为某个类型

var file1 Writer = ...
if file6, ok := file1.(*File); ok {
    ...
}

4.4 类型查询

type File struct {}

func (f *File)Write()  {
    return
}

func (f *File)Read()  {
    return
}

func (f *File)Close()  {
    return
}

type WR interface{
    Write()
    Read()
}

type W interface {
    Write()
}

func main()  {
        var wr1 WR = new(File)
        _, ok := wr1.(WR)
        fmt.Println(wr1, ok)
        switch wr1.(type){          // 类型查询语句
        case W:
            fmt.Println("type is W")
        case WR:
            fmt.Println("is WR")
        }
    }

4.5 接口组合 

type ReadWriter interace {        // ReadWriter接口将Reader接口和Writer接口组合起来
    Reader
    Writer
} 

4.6 Any类型

go语言中任何对象实例都满足空接口interface{}, 所以interface{} 看起来像是可以指向任何对象的Any类型

var v1 interface{} = 1
var v2 interface{} = "abc"
var v3 interface{} = &v2
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}

当函数可以接受任意的对象实例时, 我们会将其声明为interface{}

func Printf(fmt string, args ...interface{})
func Println(args ...interface{})

                                                                                                                                                                                                                                   

原文地址:https://www.cnblogs.com/zhangjian0092/p/12358209.html