Go语言利用接口实现链表插入功能详解

目录
  • 1. 接口定义
    • 1.1 空接口
    • 1.2 实现单一接口
    • 1.3 接口多方法实现
  • 2. 多态
    • 2.1 为不同数据类型的实体提供统一的接口
    • 2.2 多接口的实现
  • 3. 系统接口调用
  • 4. 接口嵌套
  • 5. 类型断言
    • 5.1 断言判断
    • 5.2 多类型判断
  • 6. 使用接口实现链表插入

1. 接口定义

  • Interface 类型可以定义一组方法,不需要实现,并且不能包含任何的变量,称之为接口
  • 接口不需要显示的实现,只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口,如果一个变量含有多个interface 类型的方法,那么这个变量就实现了多个接口
  • 接口又称为动态数据类型,在进行接口使用的的时候,会将接口对位置的动态类型改为所指向的类型
  • 会将动态值改成所指向类型的结构体
  • 每个接口由数个方法组成,接口的定义格式如下:

其中参数列表和返回值列表中的参数变量名可以省略

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

自定义接口步骤

① 定义接口

② 定义结构体

③ 接口实现(绑定结构体)

④ 定义接口变量,初始化结构体,调用接口实现功能

1.1 空接口

空接口就相当于一个空指针

package main

import "fmt"

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

func main() {
	//声明接口方法1
	var t Test
	fmt.Printf("t的类型: %T, t的值: %v\n", t, t)
	//声明接口方法2
	var a interface{}
	var b int
	a = b
	fmt.Printf("a的类型: %T, a的值: %v\n", a, a)
}

输出结果如下

t的类型: <nil>, t的值: <nil>
a的类型: int, a的值: 0

1.2 实现单一接口

结构体使用接口打印信息

package main

import "fmt"

type Student struct {
	Name  string
	Age   int
	Score float32
}

//接口定义:接口是功能的抽象,不需要实现
type Test interface {
	Print()
}

//指针类型实现接口
func (p *Student) Print() {
	fmt.Printf("name:[%s]\n", p.Name)
	fmt.Printf("age:[%d]\n", p.Age)
	fmt.Printf("score:[%f]\n", p.Score)
}

//值类型实现接口
/*
func (p Student) Print() {
	fmt.Printf("name:[%s]\n", p.Name)
	fmt.Printf("age:[%d]\n", p.Age)
	fmt.Printf("score:[%f]\n", p.Score)
}
*/

func main() {
	//声明接口变量
	var t Test
	//结构体初始化
	var stu Student = Student{
		Name:  "zhangsan",
		Age:   18,
		Score: 90,
	}
	//把结构体赋值给接口
	t = &stu
	//接口功能
	t.Print()
}

输出结果如下

name:[zhangsan]
name:[18]
name:[90.000000]

1.3 接口多方法实现

package main

import "fmt"

type Student struct {
	Name  string
	Age   int
	Score float32
}

//接口定义:接口是功能的抽象,不需要实现
type Test interface {
	Print()
	Sleep()
}

//接口的实现
func (p *Student) Print() {
	fmt.Printf("name:[%s]\n", p.Name)
	fmt.Printf("age:[%d]\n", p.Age)
	fmt.Printf("score:[%f]\n", p.Score)

}

//接口中包含多个方法,如果要使用此接口就要实现接口中包含的所有方法
func (p *Student) Sleep() {
	fmt.Println("正在睡眠~")
}

func main() {
	//声明接口变量
	var t Test
	//结构体初始化
	var stu Student = Student{
		Name:  "zhangsan",
		Age:   18,
		Score: 90,
	}
	//把结构体赋值给接口
	t = &stu
	//接口功能
	t.Print()
	t.Sleep()
}

输出结果如下

name:[zhangsan]
name:[18]
name:[90.000000]
正在睡眠~

示例,在电脑上定义一个USB接口,实现鼠标、U盘、风扇的功能

package main

import "fmt"

//定义电脑
type Computer struct {
	Brand string	//品牌
	Price float32	//价格
}

//定义USB接口
type USB interface {
	mouse()
	store()
	fan()
}

//接口功能实现
func (c Computer) mouse() {
	fmt.Println("鼠标")
}

func (c Computer) store() {
	fmt.Println("U盘")
}

func (c Computer) fan() {
	fmt.Println("风扇")
}

func main() {
	//初始化结构体
	var com Computer
	//初始化接口
	var usb USB
	com.Brand = "thinkpad"
	com.Price = 5000
	//接口调用
	usb = com
	usb.mouse()
	usb.fan()
	usb.store()
}

输出结果如下

鼠标
风扇
U盘

2. 多态

对于同一个接口,赋予给不同的结构体,使用相同的方法而产生出不同的操作,称之为多态。

2.1 为不同数据类型的实体提供统一的接口

package main

import "fmt"

//父结构体
type Persion struct {
	Name string
	Age  int
}

//学生子结构体
type Student struct {
	Persion
	Score float32
}

//教师子结构体
type Teacher struct {
	Persion
	Class int
}

//接口定义:接口时功能的抽象,不需要实现
type Test interface {
	Print()
	Sleep()
}

//学生结构体的实现
func (p *Student) Print() {
	fmt.Printf("name:[%s]\n", p.Name)
	fmt.Printf("age:[%d]\n", p.Age)
	fmt.Printf("Score:[%f]\n", p.Score)
}

//教师结构体的实现
func (p *Teacher) Print() {
	fmt.Printf("name:[%s]\n", p.Name)
	fmt.Printf("age:[%d]\n", p.Age)
	fmt.Printf("Class:[%d]\n", p.Class)

}

//接口中包含多个方法,如果要使用此接口就要实现接口中包含的所有方法
func (p *Student) Sleep() {
	fmt.Println("正在睡眠~")
}

func (p *Teacher) Sleep() {
	fmt.Println("正在休息~")
}

func main() {
	//声明接口变量
	var t Test
	//学生初始化
	var stu Student
	stu.Name = "zhangsan"
	stu.Age = 18
	stu.Score = 90

	//教师初始化
	var tea Teacher
	tea.Name = "lisi"
	tea.Age = 25
	tea.Class = 3

	//学生接口功能调用实现
	t = &stu
	t.Print()
	t.Sleep()
	fmt.Println("----------------------------")
	//教师接口功能调用实现
	t = &tea
	t.Print()
	t.Sleep()
}

输出结果如下

name:[zhangsan]
age:[18]
Score:[90.000000]
正在睡眠~
----------------------------
name:[lisi]
age:[25]
Class:[3]
正在休息~

2.2 多接口的实现

package main

import "fmt"

//接口1
type Test1 interface {
	Print()
}

//接口2
type Test2 interface {
	Sleep()
}

//结构体
type Student struct {
	Name  string
	Age   int
	Score float32
}

//接口1实现
func (s Student) Print() {
	fmt.Printf("name:[%s]\n", s.Name)
}

//接口2实现
func (s Student) Sleep() {
	fmt.Println("正在睡眠")
}

func main() {
	//接口1变量
	var t1 Test1
	//接口2变量
	var t2 Test2
	//初始化结构体
	var stu Student = Student{
		Name:  "zhangsan",
		Age:   18,
		Score: 90,
	}
	//调用接口实现功能
	t1 = stu
	t1.Print()

	t2 = stu
	t2.Sleep()
}

输出结果如下

name:[zhangsan]
正在睡眠

3. 系统接口调用

示例

使用接口进行排序

package main

import (
    "fmt"
    "math/rand"
    "sort"
)

//结构体
type Student struct {
    Name  string
    Age   int
    Score float32
}

//切片
type StudentArray []Student

//go语言提供了sort 接口。使用接口里的方法即可
//实现sort接口
func (sa StudentArray) Len() int {
    return len(sa)
} //获取切片长度
func (sa StudentArray) Less(i, j int) bool {
    return sa[i].Name > sa[j].Name
} //两数比大小
func (sa StudentArray) Swap(i, j int) {
    sa[i], sa[j] = sa[j], sa[i]
} //两数交换

func main() {
    //Student 切片
    var stus StudentArray

    //生成10个结构体,放入切片中
    for i := 0; i < 10; i++ {
        var stu Student = Student{
            Name:  fmt.Sprintf("stu%d", rand.Intn(100)),
            Age:   rand.Intn(120),
            Score: rand.Float32() * 100,
        }

        //结构体元素存入到切片中
        stus = append(stus, stu)
    }

    //遍历
    for _, v := range stus {
        fmt.Println(v)
    }

    fmt.Println("--------------------------")
    //排序
    sort.Sort(stus)
    //遍历
    for _, v := range stus {
        fmt.Println(v)
    }
}

4. 接口嵌套

示例:

文件读写测试

package main

import "fmt"

//读取的接口
type Reader interface {
	Read()
}

//写入的接口
type Writer interface {
	Writer()
}

//接口的嵌套
type ReadWriter interface {
	Reader
	Writer
}

//文件结构体
type File struct{}

//实现Reader接口
func (f *File) Read() {
	fmt.Println("文件读取")
}

//实现Writer接口
func (f *File) Writer() {
	fmt.Println("文件写入")
}

//定义读写操作函数
func Test(rw ReadWriter) {  //rw为接口变量
	rw.Read()				//使用读写的方法
	rw.Writer()
}

func main() {
	var f File				//定义结构体,初始化文件
	Test(&f)
}

输出结果如下

文件读取
文件写入

5. 类型断言

作用:因为接口是一般类型,需要明确具体类型的时候就需要使用类型断言

示例

package main

import "fmt"

func main() {
	//定义空接口
	var a interface{}
	var b int
	a = b //a为int类型
	//断言赋值
	fmt.Printf("a= %v, 类型: %T\n", a, a)
	c := a.(int)
	fmt.Printf("c= %v, 类型: %T\n", c, c)
}

输出结果如下

a= 0, 类型: int
c= 0, 类型: int

5.1 断言判断

package main

import "fmt"

func main() {
	//定义空接口
	var a interface{}
	var b string
	a = b //a为int类型
	//断言赋值
	fmt.Printf("a= %v, 类型: %T\n", a, a)
	c, err := a.(int)
	if err {
		fmt.Printf("c= %v, 类型: %T\n", c, c)
	} else {
		fmt.Println("不是int类型")
	}
}

输出结果如下

a= , 类型: string
不是int类型

package main

import "fmt"

func Test(t interface{}) {
	//转换类型判断
	v, err := t.(int)
	if !err {
		fmt.Println("type is not int")
		return
	}
	v++
	fmt.Println(v)
}

func main() {
	a := "张三"
	Test(a)
}

输出结果如下

type is not int

5.2 多类型判断

package main

import "fmt"

func classifier(items ...interface{}) {
	//遍历复杂集合
	for i, v := range items {
		//变量.(type)职能作用在switch语句中,专门用于判断类型
		switch v.(type) {
		case bool:
			fmt.Printf("第 %d 个数据类型是 bool\n", i)
		case int, int32, int64:
			fmt.Printf("第 %d 个数据类型是 int\n", i)
		case float32, float64:
			fmt.Printf("第 %d 个数据类型是 float\n", i)
		case string:
			fmt.Printf("第 %d 个数据类型是 string\n", i)
		default:
			fmt.Printf("第 %d 个数据类型是其他类型\n", i)
		}
	}
}

func main() {
	//传入多种类型参数
	classifier("张三", 3.14, true, 80, nil)
}

输出结果如下

第 0 个数据类型是 string
第 1 个数据类型是 float
第 2 个数据类型是 bool
第 3 个数据类型是 int
第 4 个数据类型是其他类型

6. 使用接口实现链表插入

package main

import "fmt"

//节点结构体
type LinkNode struct {
    data interface{}
    next *LinkNode
}

//链表结构体
type Link struct {
    head *LinkNode
    tail *LinkNode
}

//从头部插入
func (p *Link) InsertHead(data interface{}) {
    node := &LinkNode{
        data: data,
        next: nil,
    }
    //判断是否为空链表
    if p.head == nil && p.tail == nil {
        p.head = node
        p.tail = node
        return
    }
    //当前节点的next是原头部节点
    node.next = p.head
    //更新头部
    p.head = node
}

//从尾部插入
func (p *Link) InsertTail(data interface{}) {
    node := &LinkNode{
        data: data,
        next: nil,
    }

    //判断是否为空链表
    if p.head == nil && p.tail == nil {
        p.head = node
        p.tail = node
        return
    }

    //原尾部节点的next是当前节点
    p.tail.next = node
    //更新尾部
    p.tail = node
}

//遍历方法
func (p *Link) Req() {
    lp := p.head
    for lp != nil {
        fmt.Println(lp)
        lp = lp.next
    }
}

func main() {
    //定义链表
    var intLink Link
    for i := 0; i < 10; i++ {
        //intLink.InsertHead(i)
        intLink.InsertTail(i)
    }
    intLink.Req()
}

输出结果如下

&{0 0xc000096078}
&{1 0xc000096090}
&{2 0xc0000960a8}
&{3 0xc0000960c0}
&{4 0xc0000960d8}
&{5 0xc0000960f0}
&{6 0xc000096108}
&{7 0xc000096120}
&{8 0xc000096138}
&{9 <nil>}

到此这篇关于Go语言利用接口实现链表插入功能详解的文章就介绍到这了,更多相关Go语言接口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一篇文章带你玩转go语言的接口

    目录 一.其他语言 二.go语言 三.go接口实现多态 四.空接口的使用(重点) 4.1定义 4.2空接口使用 4.3空接口几个要注意的坑(我刚学时的错误) 总结 一.其他语言 其他语言中所提供的接口概念:接口主要作为不同组件之间的契约存在.对契约的实现是强制的(侵入式接口),你必须声明你的确实现了该接口.为了实现一个接口,你需要从该接口继承. interface IFoo { void Bar(); } // Java文法 // ... class Foo implements IFoo {

  • Go语言的接口详解

    目录 1.接口的用途 2.类型断言 3.类型选择 4.空接口 5.匿名空接口 6.实现多个接口 7.接口嵌套 8.接口零值 9.make和new的区别 总结 接口就是一系列方法的集合(规范行为) 在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为,规范子类对象的行为. 在 Go 语言中的接口是非侵入式接口(接口没了,不影响代码),侵入式接口(接口没了,子类报错) Go 也是鸭子类型,比如我现在有个鸭子类,内有 speak 方法和 run 方法,子类只要实现了 speak 和 run,我

  • 从零开始学Golang的接口

    目录 前言 1.为什么需要接口? 2.接口是什么?如何定义? 3.接口实战初体验 4.如何测试是否已实现该接口? 5.空接口&类型断言 6.接口零值 7.一个类型实现多个接口 8.指针与值类型实现接口的区别 9.接口嵌套 前言 接口在面向对象编程中是经常使用的招式,也是体现多态很重要的手段.是的.Golang中也有接口这玩意儿. 1.为什么需要接口? 多数情况下,数据可能包含不同的类型,却会有一个或者多个共同点,这些共同点就是抽象的基础.前文讲到的Golang继承解决的是is-a的问题,单一继承

  • Go基础教程系列之Go接口使用详解

    接口用法简介 接口(interface)是一种类型,用来定义行为(方法). type Namer interface { my_method1() my_method2(para) my_method3(para) return_type ... } 但这些行为不会在接口上直接实现,而是需要用户自定义的方法来实现.所以,在上面的Namer接口类型中的方法my_methodN都是没有实际方法体的,仅仅只是在接口Namer中存放这些方法的签名(签名 = 函数名+参数(类型)+返回值(类型)). 当用

  • Go语言利用接口实现链表插入功能详解

    目录 1. 接口定义 1.1 空接口 1.2 实现单一接口 1.3 接口多方法实现 2. 多态 2.1 为不同数据类型的实体提供统一的接口 2.2 多接口的实现 3. 系统接口调用 4. 接口嵌套 5. 类型断言 5.1 断言判断 5.2 多类型判断 6. 使用接口实现链表插入 1. 接口定义 Interface 类型可以定义一组方法,不需要实现,并且不能包含任何的变量,称之为接口 接口不需要显示的实现,只需要一个变量,含有接口类型中的所有方法,那么这个变量就实现了这个接口,如果一个变量含有多个

  • Go语言数据结构之单链表的实例详解

    目录 任意类型的数据域 实例01 快慢指针 实例02 反转链表 实例03 实例04 交换节点 实例05 任意类型的数据域 之前的链表定义数据域都是整型int,如果需要不同类型的数据就要用到 interface{}. 空接口 interface{} 对于描述起不到任何的作用(因为它不包含任何的method),但interface{}在需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值. 一个函数把interface{}作为参数,那么它可以接受任意类型的值作为参数:如果一个函数返回i

  • C语言实现单链表的基本功能详解

    1.首先简单了解一下链表的概念: 要注意的是链表是一个结构体实现的一种线性表,它只能从前往后,不可以从后往前(因为next只保存下一个节点的地址).在实现单链表的操作时,需要用指针来操作.很简单,注释写的很详细,欢迎大家指正哈哈哈哈~之前写的太烂了重新写了一下..... 2.代码展示: #include <stdio.h> #include <assert.h> #include <stdlib.h> typedef struct linklist { int data

  • Go语言学习之链表的使用详解

    目录 1. 什么是链表 2. 单项链表的基本操作 3. 使用 struct 定义单链表 4. 尾部添加节点 5. 头部插入节点 6. 指定节点后添加新节点 7. 删除节点 1. 什么是链表 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的. 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域. 使用链表结构可以避免在使用数组时需要预先知

  • Qt利用QDrag实现拖拽拼图功能详解

    目录 一.项目介绍 二.项目基本配置 三.UI界面设置 四.主程序实现 4.1 main.cpp 4.1 mainwindow.h头文件 4.2 mainwindow.cpp源文件 4.3 PiecesList类 4.4 PuzzleWidget类 五.效果演示 一.项目介绍 本文介绍利用QDrag类实现拖拽拼图功能.左边是打散的图,拖动到右边进行复现,此外程序还支持手动拖入原图片. 二.项目基本配置 新建一个Qt案例,项目名称为“puzzle”,基类选择“QMainWindow”,取消选中创建

  • 利用二进制文件安装etcd的教程详解

    etcd组件作为一个高可用强一致性的服务发现存储仓库. etcd作为一个受到ZooKeeper与doozer启发而催生的项目,除了拥有与之类似的功能外,更专注于以下四点. 简单:基于HTTP+JSON的API让你用curl就可以轻松使用. 安全:可选SSL客户认证机制. 快速:每个实例每秒支持一千次写操作. 可信:使用Raft算法充分实现了分布式. 场景一:服务发现(Service Discovery)一个强一致性.高可用的服务存储目录.基于Raft算法的etcd天生就是这样一个强一致性高可用的

  • Python 列表与链表的区别详解

    目录 python 列表和链表的区别 列表的实现机制 链表 链表与列表的差异 python 列表和链表的区别 python 中的 list 并不是我们传统意义上的列表,传统列表--通常也叫作链表(linked list)是由一系列节点来实现的,其中每个节点都持有一个指向下一节点的引用. class Node: def __init__(self, value, next=None): self.value = value self.next = next 接下来,我们就可以将所有的节点构造成一个

  • C语言实现顺序表的全操作详解

    目录 线性表 顺序表 顺序表接口实现 1.顺序表初始化 2.顺序表空间增容 3.顺序表打印 4.尾插数据 5.尾删数据 6.头插数据 7.头删数据 8.在pos下标处插入数据 9.删除pos下标处数据 10.数据查找 11.顺序表摧毁 线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列.线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表.链表.栈.队列.字符串等. 线性表在逻辑上是线性结构,也就是连续的一条直线.但在物理结构上并不一定是连续的,线性表在物理

  • Spring利用注解整合Mybatis的方法详解

    目录 一.环境准备 步骤1:数据库相关 步骤2:导入jar包 步骤3:创建模型类 步骤4:创建Dao接口和实现类 步骤5:创建Service接口和实现类 步骤6:添加jdbc.properties文件 步骤7:添加Mybatis核心配置文件 步骤8:编写测试程序 二.整合思路分析 三.整合步骤 步骤1:导入整合jar包 步骤2:创建数据源配置类 步骤3:创建Mybatis配置类 步骤4:创建Spring主配置类 步骤5:编写运行程序 一.环境准备 步骤1:数据库相关 建库建表 创建spring_

  • SpringBoot利用AOP实现一个日志管理详解

    目录 1. 需求 2. 新建一张日志表 3. 写相应的Controller层 4.Service接口层 5.Service实现 6.Mapper接口 7.Mapper.xml(我用的是Mybatis) 8.CspLog 9.实体类SysOperCspLog 10. 定义日志管理的切面 11.AsyncFactoryCsp 12. 写一个Controller的Demo来执行一条日志试试 1. 需求 目前有这么个问题,有两个系统CSP和OMS,这俩系统共用的是同一套日志操作:Log;目前想区分下这俩

随机推荐