Go 语言基础之面向对象编程

简介: Go 语言基础之面向对象编程

1、OOP

首先,Go 语言并不是面向对象的语言,只是可以通过一些方法来模拟面向对象

1.1、封装

Go 语言是通过结构体(struct)来实现封装的。

1.2、继承

继承主要由下面这三种方式实现:

1.2.1、嵌套匿名字段

//Address 地址结构体
type Address struct {
  Province string
  City     string
}
 
//User 用户结构体
type User struct {
  Name    string
  Gender  string
  Address //匿名字段
}
 
func main() {
  var user2 User
  user2.Name = "小王子"
  user2.Gender = "男"
  user2.Address.Province = "山东"    // 匿名字段默认使用类型名作为字段名
  user2.City = "威海"                // 匿名字段可以省略
  fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

1.2.2、嵌套结构体

//Address 地址结构体
type Address struct {
  Province string
  City     string
}
 
//User 用户结构体
type User struct {
  Name    string
  Gender  string
  Address Address
}
 
func main() {
  user1 := User{
    Name:   "小王子",
    Gender: "男",
    Address: Address{
      Province: "山东",
      City:     "威海",
    },
  }
  fmt.Printf("user1=%#v\n", user1)//user1=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

1.2.3、嵌套匿名结构体指针

//Animal 动物
type Animal struct {
  name string
}
 
func (a *Animal) move() {
  fmt.Printf("%s会动!\n", a.name)
}
 
//Dog 狗
type Dog struct {
  Feet    int8
  *Animal //通过嵌套匿名结构体实现继承
}
 
func (d *Dog) wang() {
  fmt.Printf("%s会汪汪汪~\n", d.name)
}
 
func main() {
  d1 := &Dog{
    Feet: 4,
    Animal: &Animal{ //注意嵌套的是结构体指针
      name: "乐乐",
    },
  }
  d1.wang() //乐乐会汪汪汪~
  d1.move() //乐乐会动!
}

       而既然结构体可以继承,那么结构体就必须有方法,Go 语言的方法必须在方法名前面声明调用者。子类可以重写父类方法:如果在子结构体(或任何类型)上定义了一个与父结构体中同名的方法,那么这个方法就会覆盖父结构体中的方法。这就实现了重写。

1.3、多态

多态:一个事物拥有多种形态就是多态!

有多态就必须要有接口,因为接口就是为了解决多态这个问题的:

1.3.1、接口

  • Go 语言提供了接口数据类型
  • 接口就是把一些共性的方法放在一起定义
  • Go 语言中的接口是隐式声明的(相比较 Java 会用 implements 关键字显示声明)
  • 只有实现类把接口的方法全部实现才算实现了这个接口

接口的实现类都拥有多态的特性,因为它除了是自己还是它的接口类型

package main
 
import "fmt"
 
// 接口
type USB interface {
  input()
  output()
}
 
// 结构体
type Mouse struct {
  name string
}
// 实现接口:实现了接口的所有方法才算实现了这个接口
func (mouse Mouse) input(){
  fmt.Println(mouse.name,"鼠标输入")
}
func (mouse Mouse) output(){
  fmt.Println(mouse.name,"鼠标输出")
}
 
type KeyBoard struct {
  name string
}
func (keyBoard KeyBoard) input(){
  fmt.Println(keyBoard.name,"键盘输入")
}
func (keyBoard KeyBoard) output(){
  fmt.Println(keyBoard.name,"键盘输出")
}
 
func test(u USB) {
  u.input()
  u.output()
}
 
func main() {
  mouse := Mouse{name: "罗技"}
  test(mouse)
 
  keyBoard := KeyBoard{name: "艾石头"}
  test(keyBoard)
 
    // 通过接口创建子类实例
  var usb USB = Mouse{name: "外星人"}
  usb.input()
  // 但是接口是无法使用实现类的属性的
}

运行结果:

罗技 鼠标输入
罗技 鼠标输出
艾石头 键盘输入
艾石头 键盘输出
 
外星人 鼠标输入

1.3.2、空接口

空接口不包含任何方法,所以所有的结构体都默认实现了空接口(类似于 Java 的 Object)!

所谓的空接口,就是:

type 接口名称 interface{}

go 语言中的 any 其实就是空接口,我们可以在源码中看到:

       如果我们定义一个方法或者函数它可以传入一个空接口类型,那么就相当于任何类型都可以传入这个方法或函数,因为任何结构体类型的都实现了空接口。比如我们 go 语言中的打印方法的参数就都是 any ... 。

2、接口

       上面只是描述了接口是怎么实现多态的,但是对接口的用法并没有深入介绍,这里我们详细介绍接口的用法。

2.1、接口的定义

type 接口名 interface{
    方法名1(参数列表) (返回值列表)
    方法名2(参数列表) (返回值列表)
    // ...
}

需要注意的是:

  • 接口类型名:Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有关闭操作的接口叫closer等。接口名最好要能突出该接口的类型含义。
  • 方法名当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。
  • 参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。

2.2、接口类型变量

所谓的接口类型变量就就像 Java 中的:

Map<String,Integer> map;
HashMap<String,Integer> map1 = new HashMap<>();
TreeMap<String,Integer> map2 = new TreeMap<>();
map = m1;
map = m2;

这里的变量 map 就是一个接口变量,接口变量可以通过任何实现类来赋值。

2.3、接口的嵌套

Go 语言中的接口可以组合嵌套,这是区别于 Java 很大的一点。在 Go标准库 io 源码中就有很多接口之间互相组合的示例:

// src/io/io.go
 
type Reader interface {
  Read(p []byte) (n int, err error)
}
 
type Writer interface {
  Write(p []byte) (n int, err error)
}
 
type Closer interface {
  Close() error
}
 
// ReadWriter 是组合Reader接口和Writer接口形成的新接口类型
type ReadWriter interface {
  Reader
  Writer
}
 
// ReadCloser 是组合Reader接口和Closer接口形成的新接口类型
type ReadCloser interface {
  Reader
  Closer
}
 
// WriteCloser 是组合Writer接口和Closer接口形成的新接口类型
type WriteCloser interface {
  Writer
  Closer
}

同时,接口也可以作为结构体的字段,就像 Java 中 Map 可以作为对象属性一样:

// src/sort/sort.go
 
// Interface 定义通过索引对元素排序的接口类型
type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}
 
 
// reverse 结构体中嵌入了Interface接口
type reverse struct {
    Interface
}

2.4、类型断言

       类型断言就像 Java 中的强转一样,一般是把一个抽象的接口类型转为一个确定的实现类型。好像说我们可以"断言"这个接口类型一定是这个实现类类型。

2.4.1、语法

x.(T)
  • x:表示接口类型的变量(如果不是接口类型的就在前面加上空接口)
  • T:表示断言 x 是 T 类型

注意:类型断言的返回结果是两个参数,第一个返回值是一个转为断言类型后的变量,第二个返回值是转为断言的结果(布尔类型,代表成功/失败)

       对于数值类型( 比如 int、string、float64... )这些不是接口类型的数据,如果要做类型断言就需要给它前面加个空接口,因为所有类型都是隐式地实现了空接口的。

    str := "10"
    // 第2个返回值是断言结果
  res,_ := interface{}(str).(int)
  fmt.Println(res) // 10

       对于接口类型变量,如果我们能知道它是哪个实现类型就可以直接进行类型断言:

    ​​var usb USB = Mouse{name: "外星人"}
    // 类型断言 这里没有接收第二个返回值,代表丢弃
  m := usb.(Mouse)
  fmt.Println(m)

       上面的 USB 是接口类型,而它的地址指向一个 Mouse 类型的实例,所以我们可以断言这个 USB 实例一定是 Mouse 类型。

相关文章
|
8天前
|
安全 测试技术 Go
Go语言在高并发场景下的应用
在当今互联网高速发展的时代,高并发已成为众多应用系统面临的核心问题。本文探讨了Go语言在高并发场景下的优势,并通过具体实例展示了其在实际应用中的效果和性能表现。
|
5天前
|
Go
go语言map、实现set
go语言map、实现set
12 0
|
5天前
|
Go
go语言数组与切片
go语言数组与切片
14 0
|
1天前
|
JSON 算法 测试技术
在go语言中调试程序
【6月更文挑战第29天】Go语言内置`testing`包支持单元测试、基准测试和模糊测试。`go test`命令可执行测试,如`-run`选择特定测试,`-bench`运行基准测试,`-fuzz`进行模糊测试。
12 2
在go语言中调试程序
|
7天前
|
存储 中间件 Go
在go语言服务中封装路由和示例
【6月更文挑战第23天】本文介绍golang后端按协议处理、中间件(一次性与每次请求执行)划分、以及服务架构Controller、Logic/Service、DAO/Repository和Routers划分。代码仓库在GitHub上提供。使用框架简化了交互和处理。后续章节深入探讨服务构建。
105 5
在go语言服务中封装路由和示例
|
4天前
|
Devops Go 云计算
Go语言发展现状:历史、应用、优势与挑战
Go语言发展现状:历史、应用、优势与挑战
|
5天前
|
Go
go语言的hello,world
go语言的hello,world
10 1
|
3天前
|
编译器 Go C++
必知的技术知识:go语言快速入门教程
必知的技术知识:go语言快速入门教程
|
4天前
|
编译器 Go 开发者
|
5天前
|
Java Go Windows
go语言实现加减法出题器(再也不用担心孩子学习了)
go语言实现加减法出题器(再也不用担心孩子学习了)
10 0