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

1、OOP

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

1.1、封装

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

1.2、继承

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

1.2.1、嵌套匿名字段

//Address 地址结构体
type Address struct {Province stringCity     string
}//User 用户结构体
type User struct {Name    stringGender  stringAddress //匿名字段
}func main() {var user2 Useruser2.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 stringCity     string
}//User 用户结构体
type User struct {Name    stringGender  stringAddress 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 mainimport "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.gotype 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 {ReaderWriter
}// ReadCloser 是组合Reader接口和Closer接口形成的新接口类型
type ReadCloser interface {ReaderCloser
}// WriteCloser 是组合Writer接口和Closer接口形成的新接口类型
type WriteCloser interface {WriterCloser
}

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

// src/sort/sort.go// Interface 定义通过索引对元素排序的接口类型
type Interface interface {Len() intLess(i, j int) boolSwap(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 类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/7866.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CoPilot 产品体验:提升 OpenNJet 的控制管理和服务提供能力

文章目录 前言系统架构介绍CoPilot 配置CoPilot 插件规范 体验 CoPilot 实例CoPilot: Broker 实例CoPilot: Ctrl 实例 开发其他语言编写的 CoPilot目标主要思路具体实现执行 go 程序代码 功能扩展总结 前言 CoPilot 是 OpenNJet 的一个重要组成部分&#xff0c;它在 Master-Wo…

246 基于matlab的交流电机动态方程

基于matlab的交流电机动态方程&#xff0c;用于交流电机动态分析。输入电机的额定功率(kW)、电机的额定转速(r/min)、转子外径(m)、铁心长(m)转子槽数、电机极对数 等参数&#xff0c;输出转速变化、力矩变化等结果。程序已调通&#xff0c;可直接运行。 246 交流电机动态 转速…

DAY 2

winget.cpp #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {this->resize(540,415);this->setFixedSize(540,415);//窗口标题this->setWindowTitle("盗版QQ");//窗口图标this->setWindowIcon(QIcon("E:\\qq\\pi…

30分钟打造属于自己的Flutter内存泄漏检测工具---FlutterLeakCanary

30分钟打造属于自己的Flutter内存泄漏检测工具 思路检测Dart 也有弱引用-----WeakReference如何执行Full GC&#xff1f;如何知道一个引用他的文件路径以及类名&#xff1f; 代码实践第一步&#xff0c;实现Full GC第二步&#xff0c;如何根据对象引用&#xff0c;获取出他的类…

HarmonyOS实战开发教程-如何开发一个2048游戏

今天为大家分享的是2048小游戏&#xff0c;先看效果图&#xff1a; 这个项目对于新手友友来说可能有一点难度&#xff0c;但是只要坚持看完一定会有收获。因为小编想分享的并不局限于ArkTs语言&#xff0c;而是编程思想。 这个游戏的基本逻辑是初始化一个4乘4的数组&#xff…

LeetCode 每日一题 Day 144-157

2385. 感染二叉树需要的总时间 给你一棵二叉树的根节点 root &#xff0c;二叉树中节点的值 互不相同 。另给你一个整数 start 。在第 0 分钟&#xff0c;感染 将会从值为 start 的节点开始爆发。 每分钟&#xff0c;如果节点满足以下全部条件&#xff0c;就会被感染&#xf…

网络基础(1)网络编程套接字TCP,守护进程化

TCP协议 下面我们来学习一下TCP套接字的使用。 也就是使用一下基本的接口。首先TCP套接字的使用和UDP套接字的使用是大同小异的&#xff0c;但是多了一些步骤。 这里回顾一下&#xff1a;UDP是不可靠的&#xff0c;无连接的协议。而TCP则是可靠的&#xff0c;面向连接的协议…

[HUBUCTF 2022 新生赛]checkin

数组反序列化弱比较 <?php $info array(username>true,password>true); echo serialize($info); ?> //?infoa:2:{s:8:"username";b:1;s:8:"password";b:1;}1.构造不能用类&#xff0c;因为$data_unserialize只是一个变量&#xff0c;不能…

vivado Versal ACAP 可编程器件镜像 (PDI) 设置

Versal ACAP 可编程器件镜像 (PDI) 设置 下表所示 Versal ACAP 器件的器件配置设置可搭配 set_property <Setting> <Value> [current_design] Vivado 工具 Tcl 命令一起使用。 注释 &#xff1a; 在 Versal ACAP 架构上 &#xff0c; 原先支持将可编程器…

游戏技术人福音!当游戏语音碰到网易云信 ,我服了!

“开黑吗&#xff1f;五黑的那种” 少年时代&#xff0c;放假后偷偷溜进网吧&#xff0c;一边打着游戏&#xff0c;一边连麦吐槽对手的惬意岁月&#xff0c;不仅承载了无数 80 后、90 后&#xff0c;甚至 00 后的青春记忆&#xff0c;也让游戏语音成为了“游戏少年”闲暇生活的…

6W 1.5KVDC. 单、双输出 DC/DC 电源模块——TP2L-6W 系列

TP2L-6W系列是一款高性能、超小型的电源模块&#xff0c;2:1电压输入&#xff0c;输出有稳压和连续短路保护功能&#xff0c;隔离电压为1.5KVDC、作温度范围为–40℃到85℃。特别适合对输出电压的精度有严格要求的地方&#xff0c;外部遥控功能对您的设计又多一项选择&#xff…

HackMyVM-Slowman

目录 信息收集 arp nmap whatweb WEB web信息收集 gobuster FTP匿名登录 hydra mysql爆破 mysql登录 fcrackzip爆破 hashcat爆破 ssh登录 提权 系统信息收集 python Capabilities提权 信息收集 arp ┌──(root㉿0x00)-[~/HackMyVM] └─# arp-scan -l Interf…

类加载器aa

一&#xff0c;关系图及各自管辖范围 &#xff08;不赘述&#xff09; 二&#xff0c;查看关系 package com.jiazai;public class Main {public static void main(String[] args) {ClassLoader appClassLoader ClassLoader.getSystemClassLoader();//默认System.out.println…

关于在Conda创建的虚拟环境中安装好OpenCV包后,在Pycharm中依然无法使用且import cv2时报错的问题

如果你也掉进这个坑里了&#xff0c;请记住opencv-python&#xff01;opencv-python&#xff01;&#xff01;opencv-python&#xff01;&#xff01;&#xff01; 不要贪图省事直接在Anaconda界面中自动勾选安装libopencv/opencv/py-opencv包&#xff0c;或者在Pycharm中的解…

Linux搭建http发布yum源

1、搭建http源yum仓库 &#xff08;1&#xff09;在yum仓库服务端安装httpd yum -y install httpd &#xff08;2&#xff09;修改配置文件 我们httpd 中默认提供web 界面的位置是我们/var/www/html 目录&#xff0c;如果我们yum 源想指定目录&#xff0c;就需要修改蓝框2处…

VUE v-for 数据引用

VUE 的数据引用有多种方式。 直接输出数据 如果我们希望页面中直接输出数据就可以使用&#xff1a; {{ pageNumber }}双括号引用的方式即可。 在 JavaScript 中引用 如果你需要直接在代码中使用&#xff0c;直接使用变量名就可以了。 上面这张小图&#xff0c;显示了引用的…

linux 调试-kdb 调试内核-1

目标&#xff1a;打印bcm2835_spi_transfer_one 是如何从用户空间开始调用的 1. kernel 配置 KDB配置选项 添加 spi 控制器驱动 和 spi 设备驱动 2. 调试流程 调试内核-系统启动之后 1. 开发板进入kdb,等待pc 连接 rootraspberrypi:~# echo "ttyS0,115200"…

找不到模块“vue-router”。你的意思是要将 moduleResolution 选项设置为 node,还是要将别名添加到 paths 选项中?

在tsconfig.app.json中添加&#xff0c;记得一定是 tsconfig.app.json 中&#xff0c;如添加到 tsconfig.node.json 还是会报错的 哈哈哈哈&#xff0c;不瞒你们&#xff0c;我就添加错了&#xff0c;哈哈哈。所以这也算写一个demo提醒自己 "compilerOptions": {&qu…

C语言 动态内存管理

目录 1. C/C程序的内存分配2. 动态内存分配的作用3. malloc - 分配内存4. free - 释放内存5. calloc - 分配并清零内存6. realloc - 调整之前分配的内存块7. 常见的动态内存的错误7.1 对空指针解引用7.2 对动态开辟空间的越界访问7.3 对非动态开辟内存使用free7.4 使用free释放…