【Golang】Go语言接口与多态

news2024/11/18 8:52:05

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

在这里插入图片描述

文章目录

  • 接口与多态
    • 1. 接口
      • 1. 接口的定义
      • 2. 接口应用代码示例
    • 2. 模拟多态
    • 3. 空接口
    • 4. 接口嵌套
    • 5. 接口断言

接口与多态

1. 接口

1. 接口的定义

1、Go语言提供了接口数据类型。
2、接口就是把一些共性的方法集合在一起定义。
3、如果有实现类将接口定义的方法全部实现了,那么就代表实现了这个接口
4、隐式实现 Go ,假设A实现了B接口中的所有方法,不需要显示声明
5、接口是方法的定义集合,不需要实现具体的方法内容。名字约束

在Go语言中,接口(Interface)是一个重要的特性,它允许我们定义一组方法但不实现它们,任何类型只要实现了这些方法,就被认为是实现了该接口。
接口体现了程序设计的多态、高内聚、低耦合的思想,是实现面向对象编程中多态性的关键工具。

接口通过interface关键字定义,它是一组方法的集合。接口中的方法没有实现体,即它们没有具体的实现代码。一个类型只要实现了接口中的所有方法,就认为该类型实现了该接口。
如果一个结构体实现了这个接口所有的方法,那这个结构体就是这个接口类型的

2. 接口应用代码示例

接口的基本语法如下:

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

import (
    "fmt"
)

// 接口: USB、typec、插座
// 1、Go语言提供了接口数据类型。
// 2、接口就是把一些共性的方法集合在一起定义。
// 3、如果有实现类将接口定义的方法全部实现了,那么就代表实现了这个接口
// 4、隐式实现 Go ,假设A实现了B接口中的所有方法,不需要显示声明
// 5、接口是方法的定义集合,不需要实现具体的方法内容。名字约束

// USB 接口的定义 interface 来定义,方法太多了,要归类,方法的集合
type USB interface { // 接口,方法的集合
    input()  // 输入方法
    output() // 输出方法
}

// Mouse 结构体
type Mouse struct {
    name string
}

// 结构体实现了接口的全部方法就代表实现了这个接口,否则不算实现这个接口
func (mouse Mouse) output() {
    fmt.Println(mouse.name, "鼠标输出")
}
func (mouse Mouse) input() {
    fmt.Println(mouse.name, "鼠标输入")
}

// 接口调用测试
func test(u USB) {
    u.input()
    u.output()
}

func main() {
    // 通过传入接口实现类来进行调用
    m1 := Mouse{name: "罗技"}
    // test 参数 USB 类型,如果一个结构体实现了这个接口所有的方法,那这个结构体就是这个接口类型的
    test(m1)
    //也可以单独测试接口
    //m1.input()

    k1 := KeyBoard{name: "雷蛇"}
    test(k1)

    // 定义高级类型  k1就升级了  KeyBoard --> USB  向上转型
    var usb USB
    usb = k1
    fmt.Println(usb)
    // 接口是无法使用实现类的属性的
    //fmt.Println(usb.name)

}

// KeyBoard 结构体
type KeyBoard struct {
    name string
}

// 结构体实现了接口的全部方法就代表实现了这个接口,否则不算实现这个接口
func (key KeyBoard) output() {
    fmt.Println(key.name, "键盘输出")
}
func (key KeyBoard) input() {
    fmt.Println(key.name, "键盘输入")
}

在这里插入图片描述

带有参数和返回值的接口

package main

import "fmt"

// Tongxin 定义接口
type Tongxin interface {
    //定义带有参数和返回值的方法
    dadianhua(youdian bool) string
    jieidanhua(youdian bool) string
}

// People 定义结构体
type People struct {
    name  string
    age   int
    phone string
}

// 实现接口
func (p People) dadianhua(youdian bool) string {
    if youdian {
        return fmt.Sprintf("%v 打了电话", p.name)
    } else {
        return fmt.Sprintf("打电话时手机没电了")
    }

}

func (p People) jieidanhua(youdian bool) string {
    if youdian {
        return fmt.Sprintf("%v 接了电话", p.name)
    } else {
        return fmt.Sprintf("接电话时手机没电了")
    }

}

// 接口测试,有传参,有返回值
func testdianhua(phone Tongxin) {
    str1 := phone.dadianhua(false)
    str2 := phone.jieidanhua(true)
    fmt.Println(str1, str2)
}

func main() {
    //创建对象
    p := People{"jingtian", 18, "18898985898"}
    //如果一个结构体实现了这个接口所有的方法,那这个结构体就是这个接口类型的
    testdianhua(p)

}

在这里插入图片描述

2. 模拟多态

多态是指相同的接口(方法)可以表现出不同的行为。在Go语言中,通过接口实现多态。
在Go语言中,接口定义了一组方法的集合,但不实现它们,而是由具体的类型来实现这些方法。
任何实现了接口中所有方法的类型都被视为该接口的实现。接口是Go语言中实现多态性的关键。

多态:一个事务有多种形态
父类:动物
子类:猫
子类:狗

猫和狗是多态的,他们既可以是自己,也可以是动物,这个就是多态,一个事务有多种形态

Go语言中多态的实现
定义接口
首先,我们需要定义一个接口,该接口包含了一组需要被实现的方法。例如,我们可以定义一个Shape接口,用于计算不同形状的面积。

type Shape interface {  
    Area() float64  
}

在这个接口中,我们定义了一个Area()方法,该方法返回一个float64类型的值,表示形状的面积。

实现接口
接下来,我们需要定义具体的类型来实现这个接口。这些类型将提供Area()方法的具体实现。
矩形

type Rectangle struct {  
    Width  float64  
    Height float64  
}  
  
func (r Rectangle) Area() float64 {  
    return r.Width * r.Height  
}

圆形

type Circle struct {  
    Radius float64  
}  
  
func (c Circle) Area() float64 {  
    return math.Pi * c.Radius * c.Radius  
}

使用接口进行多态调用
现在,我们可以使用Shape接口来创建不同类型的形状对象,并通过接口进行多态调用。

func main() {  
    r := Rectangle{Width: 4, Height: 5}  
    c := Circle{Radius: 3}  
  
    shapes := []Shape{r, c}  
  
    for _, shape := range shapes {  
        fmt.Printf("Area: %f\n", shape.Area())  
    }  
}

完整代码

package main

import (
    "fmt"
    "math"
)

type Shape interface {
    Area() float64
}

// Rectangle 矩形
type Rectangle struct {
    Width  float64
    Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// Circle 圆形
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return math.Pi * c.Radius * c.Radius
}

func main() {
    r := Rectangle{Width: 4, Height: 5}
    c := Circle{Radius: 3}

    shapes := []Shape{r, c}

    for _, shape := range shapes {
        fmt.Printf("Area: %f\n", shape.Area())
    }
}

在这里插入图片描述

在上面的代码中,我们创建了一个shapes切片,该切片包含了不同类型的形状对象(矩形和圆形)。
然后,我们遍历shapes切片,并通过Shape接口调用Area()方法。由于这两种形状都实现了Shape接口,因此多态性使我们能够以一致的方式调用它们的Area()方法。

多态案例2:

package main

import "fmt"

// Animal3 定义接口
type Animal3 interface {
    eat()
    sleep()
}

type Dog3 struct {
    name string
}

func (dog Dog3) eat() {
    fmt.Println(dog.name, "--eat")
}
func (dog Dog3) sleep() {
    fmt.Println(dog.name, "--sleep")
}

// 多态
func main() {

    // Dog 两重身份:1、Dog   2、Animal ,多态
    dog1 := Dog3{name: "旺财"}
    dog1.eat()
    dog1.sleep()

    // Dog 也可以是 Animal
    test2(dog1)

    // 定义一个类型可以为接口类型的变量
    // 实际上所有实现类都可以赋值给这个对象
    var animal Animal3 // 模糊的 -- 具体化,将具体的实现类赋值给他,才有意义
    animal = dog1
    //接口是无法使用实现类的属性的
    test2(animal)
}

// Animal 接口
func test2(a Animal3) {
    a.eat()
    a.sleep()
}

在这里插入图片描述

接口的实现类都拥有多态特性:除了自己本身还是他对应接口的类型。

3. 空接口

空接口interface{}不包含任何方法,因此任何类型都实现了空接口。空接口可以被视为能装入任意数量、任意数据类型的数据容器。
因此空接口可以存储任何的类型
空接口不好记,因此在新版本go中起了个名字,叫any

interface{}  == any 

之所以我们的fmt.Println能打印所有东西,就是因为它传入的参数就是any,而any的类型就是空接口
在这里插入图片描述

点击any进去看看,就是空接口
在这里插入图片描述

package main

import "fmt"

// A 定义空接口
type A interface{}

// Dogg 所有结构体都实现了空接口A
type Dogg struct {
    name string
}

type Catt struct {
    name string
}

func testNow(a A) {
    fmt.Println(a)
}

// 可以指定定义空接口
// // any is an alias for interface{} and is equivalent to interface{} in all ways.
// type any = interface{}
// 可以传入任何东西
func testNow2(temp interface{}) {
}

func main() {
    //A类型可以是任何类型
    var a1 A = Catt{name: "喵喵"}
    var a2 A = Dogg{name: "旺财"}
    var a3 A = 1
    var a4 A = "景天科技苑"
    fmt.Println(a1)
    fmt.Println(a2)
    fmt.Println(a3)
    fmt.Println(a4)

    testNow(a1)

    // map结合空接口,就可以存储任何类型数据
    map1 := make(map[string]interface{})
    map1["name"] = "dajiang"
    map1["age"] = 18
    fmt.Println(map1)

    // slice,切片定义成空接口类型,也可以存放任何类型数据
    s1 := make([]any, 0, 10)
    s1 = append(s1, 1, "12312", false, a1, a2)
    fmt.Println(s1)

    //数组空接口,数组里面的值默认是nil,也可以存放任何数据类型
    var arr [4]interface{}
    fmt.Println(arr)
    arr[0] = 3
    arr[1] = "2"
    arr[2] = s1
    arr[3] = true
    fmt.Println(arr)

}

在这里插入图片描述

4. 接口嵌套

接口可以嵌套其他接口,即一个接口可以继承多个别的接口。这时,如果要实现这个接口,必须实现它继承的所有接口的方法。

package main

import (
    "fmt"
)

type AA interface {
    test1()
}
type BB interface {
    test2()
}

// CC 接口嵌套  CC :  test1()/test2()/test3()
// 如果要实现接口CC,那么需要实现这个三个方法。那这个对象就有3个接口可以转型。
type CC interface {
    AA // 导入AA接口中的方法
    BB
    test3()
}

// Dog7 编写一个结构体实现接口CC
type Dog7 struct {
}

func (dog Dog7) test1() {
    fmt.Println("test1")
}
func (dog Dog7) test2() {
    fmt.Println("test2")
}
func (dog Dog7) test3() {
    fmt.Println("test3")
}

func main() {
    // dog 拥有4种形态: Dog7 、CC 、 BB 、 AA
    var dog Dog7 = Dog7{}
    dog.test1()
    dog.test2()
    dog.test3()

    // 接口对象只能调用自己接口里面的方法
    var a AA = dog
    a.test1()
    //a.test2() // 向上转型之后只能调用它自己对应的方法
    var b BB = dog
    b.test2()

    //c三个方法都可以调用
    var c CC = dog
    c.test1()
    c.test2()
    c.test3()
}

在这里插入图片描述

5. 接口断言

接口断言用于检查接口变量是否持有特定类型的值,并获取该值。被断言的对象必须是接口类型,否则会报错
它有两种形式:不安全断言和类型安全的断言。

不安全断言
instance := 接口对象.(实际类型)
如果不满足类型断言,程序将发生panic报错。

package main

import "fmt"

// 断言  t := i.(T)   t:t就是i接口是T类型的  i:接口   T:类型
// 语法:t,ok:= i.(T) ok 隐藏返回值,如果断言成功 ok就是true、否则就是false

func main() {
    //assertsString("11111111111")
    assertsString(true) // panic: interface conversion: interface {} is bool, not string

}

// 判断一个变量是不是string类型的
func assertsString(i interface{}) {
    // 如果断言失败,则会抛出 panic 恐慌,程序就会停止执行。
    s := i.(string)
    fmt.Println(s)
}

在这里插入图片描述

类型安全的断言
instance, ok := 接口对象.(实际类型)
语法:t,ok:= i.(T) ok 隐藏返回值,如果断言成功 ok就是true、否则就是false
如果断言失败,ok将会是false,而instance将会是类型的零值,并且不会触发panic。

接口断言代码示例

package main

import "fmt"

// 断言  t := i.(T)   t:t就是i接口是T类型的  i:接口   T:类型
// 语法:t,ok:= i.(T) ok 隐藏返回值,如果断言成功 ok就是true、否则就是false

func main() {
    //assertsString("11111111111")

    assertsInt("中国")
}



// 断言失败的情况,我们希望程序不会停止。
func assertsInt(i any) {
    r, ok := i.(int)
    if ok {
        fmt.Println("是我们期望的结果 int")
        fmt.Println(r)
    } else {
        fmt.Println("不是我们期望的结果,无法执行预期操作")
    }

}

在这里插入图片描述

多个预期结果判断
通过switch来判断 switch i.(T)

i 必须是接口类型
i.(type)必须在switch中使用
在这里插入图片描述

package main

import "fmt"

// 通过switch来判断  switch i.(T)

type I interface{}

// 如果断言的类型同时实现了switch 多个case匹配,默认使用第一个case
// 所以要把范围更小的匹配放前面
func testAssert(i interface{}) {

    // switch i.(type) 接口断言
    //i.(type)必须在switch中使用
    switch i.(type) {
    case string:
        fmt.Println("变量为string类型")
    case int:
        fmt.Println("变量为int类型")
    case nil:
        fmt.Println("变量为nil类型")
    case map[string]int:
        fmt.Println("map类型")
    case interface{}:
        fmt.Println("变量为interface{}类型")
    //空接口与I一样
    case I:
        fmt.Println("变量为I类型")

    // .....
    default:
        fmt.Println("未知类型")
    }
}

func main() {

    testAssert("string")
    testAssert(1)
    var i I      // 没有初始化空接口时,默认值为 nil类型 不属于I类型
    var i2 I = 1 // 只有赋值了之后,才是对应的类型

    testAssert(i)
    testAssert(i2)

    //map类型
    j := make(map[string]int)
    testAssert(j)

}

在这里插入图片描述

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

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

相关文章

106.WEB渗透测试-信息收集-FOFA语法(6)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:105.WEB渗透测试-信息收集-FOFA语法(5) FOFA语法案例&#xff1a…

金融领域的人工智能——Palmyra-Fin 如何重新定义市场分析

引言 DigiOps与人工智能 正在改变全球各行各业,并带来新的创新和效率水平。人工智能已成为金融领域的强大工具,为市场分析、风险管理和决策带来了新方法。金融市场以复杂性和快速变化而闻名,人工智能处理大量数据并提供清晰、可操作的见解的…

影刀---实现我的第一个抓取数据的机器人

你们要的csdn自动回复机器人在这里文末哦! 这个上传的资源要vip下载,如果想了解影刀这个软件的话可以私聊我,我发你 目录 1.网页对象2.网页元素3.相似元素组4.元素操作设置下拉框复选框滚动条获取元素的信息 5.变量6.数据的表达字符串变量列…

企业身份安全管理面临的问题和解决方案

企业在向数字化、移动化、智能化加速发展的过程中,需加大信息化建设与数字化转型的投入已成为共识。企业建设的系统数量逐渐增多,部分企业甚至存在上千套信息化系统,且类型繁多: 办公系统:HR、OA、邮件、考勤等系统核心…

【Linux】通过内核以太层可查看应用程序运行时访问外网情况

比如,SourceInsight3.exe从外网接收信息: 下边是运行firefox时内核打印的日志,可以看到浏览器运行时调用了很多的操作系统内核系统调用,比如:文件读写、网络数据包的收发等等,其实这些日志还并不全&#x…

Qt-QListWidget多元素控件(36)

目录 多元素控件介绍 xxWidget和xxView的区别 描述 属性 方法 增加 删除 信号 使用 图形化界面操作 代码操作 多元素控件介绍 首先我们要先了解一下多元素控件是什么意思,一般而言是以以下这六个控件来进行区别的 xxWidget和xxView的区别 举个例子 描述…

寻找情感MV视频素材:热门素材网站推荐

在MV创作中,情感表达至关重要,唯美而深情的画面能迅速引发观众的共鸣,从而增强作品的感染力。不论你是制作爱情、失恋、亲情还是友情主题的MV,找到合适的情感视频素材都是成功的关键。如果你想为作品增添温暖和深情的氛围&#xf…

PowerPoint技巧:将幻灯片里的图片背景设置为透明

在PPT中添加了图片,想要将图片中的背景设置为透明或者想要抠图,有什么方法吗?今天分享两个方法。 方法一: 添加图片,选中图片之后,点击【图片格式】功能,点击最左边的【删除背景】 PPT会自动帮…

如何在 macOS 上恢复未保存的 Excel 文件 – 文件恢复的最佳方法

Microsoft Excel 主要用于学生、员工和组织创建电子表格、报告和许多其他内容。我们是人,我们也容易忘记事情。因此,您想要在 macOS 上恢复未保存的 Excel 文件并不罕见。 虽然在 Excel 上恢复未保存的电子表格很容易,但在 macOS 上就有些棘…

【C++掌中宝】类和对象(一):类的定义和实例化

文章目录 引言1. 什么是类?1.1 类的定义1.1.1 类定义格式1.1.2 访问限定符1.1.3 类域 1.2 类在编程中的作用——抽象与封装 2. 类的基本组成2.1 成员变量:类的属性(变量)2.2 成员函数:类的行为(函数&#x…

ai教我校验“顺序”四则运算expression(re“非捕获组”应用)

与ai学伴聊天对掐,学到了re非捕获组匹配。 (笔记模板由python脚本于2024年09月25日 23:21:14创建,本篇笔记适合初通Python,熟悉六大基本数据(str字符串、int整型、float浮点型、list列表、tuple元组、set集合、dict字典)的coder翻阅) 【学习的…

手机使用技巧:如何修复变砖的 Android 手机

许多 Android 用户选择 root Android 手机以获取更多权限。但您应该知道,除了许多好处之外,root 过程中的一些不正确的操作很容易导致一些意外情况。例如,一些用户说他们的 Android 设备在 root 之后变成了砖头手机。 如果不幸手机变砖了&am…

数字化转型:开启未来发展新引擎

在当今飞速发展的时代,数字化转型已成为企业、组织乃至整个社会发展的关键趋势。 信息技术的迅猛发展,如互联网、大数据、人工智能等,为数字化转型提供了强大支撑。市场竞争的加剧,也促使企业不断寻求提升竞争力的方法&#xff0c…

【TabBar嵌套Navigation案例-检查新版本-点击Cell执行方法 Objective-C语言】

一、接下来,我们来说这个检查新版本的功能 1.首先呢,在我们的示例程序当中, 当你点击检查新版本Cell的时候,它会弹出一个框, 这个弹框啊,就是点击cell的时候,执行了一个方法, 然后在这个方法里边,写了一个弹框, 根本的目的啊,就是要去做到,如何点击一个Cell,执行…

PyCharm 的安装和配置

环境要求: OS:Windows / macOS / Linux (此处使用 Windows 10 进行演示)Python:包括但不限于 Anaconda,miniconda,Python。在 Windows 下只要能找到 python.exe 即可 Download 进入 PyCharm 官网,选择对…

计算栅格时序数据的斜率并提取特定斜率范围的栅格

计算栅格时序数据的斜率 1 数据和软件2 计算时序栅格斜率2.1 在ENVI中安装斜率计算器插件2.2 波段合成2.3 计算斜率2.4 导出斜率栅格为tif 3 提取特定斜率范围的栅格 前言 本文所说的时序数据,本质上是多波段数据,理论上可以有无数个波段,但是…

【含文档】基于Springboot+微信小程序 的高校二手商品交易平台(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

电子级四甲基氢氧化铵 (TMAH)行业调研:预计2030年全球市场规模将达到10亿美元

四甲基氢氧化铵 (TMAH) 是一种化合物。它是一种季铵盐,其中铵离子完全被四个甲基取代,并与氢氧离子配对。TMAH 通常存在于水溶液或甲醇溶液中,在那里它以强碱的形式存在。电子级四甲基氢氧化铵 (TMAH) 是一种高纯度化合物,主要用于…

黑马头条day3-3自媒体接口作业

黑马头条day3-3自媒体接口作业 1)素材管理 1.1)图片删除 接口描述 说明接口路径/api/v1/material/del_picture/{id}请求方式GET参数Integer id响应结果ResponseResult 返回结果实例: 实现思路 感觉删除比较难写 因为需要判断图片是不是和文章挂钩了 gpt帮了很…

Python模拟真人鼠标轨迹算法

一.鼠标轨迹模拟简介 传统的鼠标轨迹模拟依赖于简单的数学模型,如直线或曲线路径。然而,这种方法难以捕捉到人类操作的复杂性和多样性。AI大模型的出现,能够通过深度学习技术,学习并模拟更自然的鼠标移动行为。 二.鼠标轨迹算法实…