Go学习之路:方法和接口(DAY 3)

news2024/11/25 4:50:41

文章目录

    • 前引
    • 方法和接口
      • 1.1、方法/声明方法
      • 1.2、方法/捆绑其他类型
      • 1.3、方法/方法常用指针传递
      • 1.4、方法/普通函数指针传递和方法指针传递区别
      • 2.1、接口/方法签名集合
      • 2.2、接口/接口断言
      • 2.3、接口/switch case
      • 练习题、接口/stringer实现字符串打印
      • 2.4、接口/错误


前引


昨天终于算是回到了家 和我爸妈好好聊了很久
在学校的日子 艰难且难熬 学习效率极低 且吃的也是相当的糟糕
感觉每天都是度日如年 我每天都在盼着出来的日子 能够离开学习 离开重庆的日子

尽管距离进部门还有一些日子 而且材料也都没有填写 但是理应这些日子我应该忙些什么 而不是什么都不干
在家里隔离三天 总算是安稳下来了 晚上还要和朋友打游戏 那么今天就把Go最后的两部分解决了吧

原谅我厚颜无耻的把DAY 3写上 尽管隔了很多天
如果这三天没有隔离在家里面 我还是想再回到省图书馆的 毕竟那是我留在成都的最多的回忆之地

下面来看看有啥吧


方法和接口


1.1、方法/声明方法


方法本质上就是一个普通函数 只是类似于c++中将成员函数和类中的数据结构成员分开

方法的声明方式是 func (struct name) funcname(type) returntype {}
和普通函数不一样的地方是在于 在参数前面多了个括号


下面简单写了个链表插入

package main

import (
	"fmt"
	"math/rand"
)

type Node struct {
	val int
	Prev *Node
	Next *Node
}

func (node *Node) AddNode(nodeptr *Node) {
	nextptr := node.Next
	prevptr := node
	nextptr.Prev = nodeptr
	prevptr.Next = nodeptr
	nodeptr.Next = nextptr
	nodeptr.Prev = prevptr
}

func main() {
	dummyhead, dummytail := Node{val : -1}, Node{val: -1}
	dummyhead.Next = &dummytail
	dummytail.Prev = &dummyhead

	for i := 0; i < 10; i++ {
		randint := rand.Int() % 100
		fmt.Printf("%d ", randint)
		insertnode := &Node{val : randint}
		dummyhead.AddNode(insertnode)
	}
	fmt.Println()

	for now := dummytail.Prev; now != &dummyhead; {
		fmt.Printf("%d ", now.val)
		now = now.Prev
	}
}


运行效果
在这里插入图片描述


1.2、方法/捆绑其他类型


1、不能捆绑基础类型 想要捆绑基础类型的方法只有利用别名
2、只能在同一个包内创建的类型对其声明方法 不能跨包
省流:接收者的类型定义和方法声明必须在同一包内;不能为内建类型声明方法


在这里插入图片描述


1.3、方法/方法常用指针传递


golang是没有引用这种说法的 c++中有引用
如果我们是直接传输的指针 是对底层的结构体修改

而如果值传递 就类似于值拷贝
而如果我们要用指针的话 是修改的结构体底层的值

所以通常捆绑的的是指针


下面测试的就是值传递

package main

import (
	"fmt"
	"math/rand"
)

type Node struct {
	val int
	Prev *Node
	Next *Node
}

func (node Node) AddNode(nodeptr Node) {
	nextptr := node.Next
	prevptr := &node
	fmt.Printf("copyptr : %p\n", &nodeptr)
	nextptr.Prev = &nodeptr
	prevptr.Next = &nodeptr
	nodeptr.Next = nextptr
	nodeptr.Prev = prevptr
}

func main() {
	dummyhead, dummytail := Node{val : -1}, Node{val: -1}
	dummyhead.Next = &dummytail
	dummytail.Prev = &dummyhead

	for i := 0; i < 10; i++ {
		randint := rand.Int() % 100
		fmt.Printf("%d ", randint)
		insertnode := Node{val : randint}
		fmt.Printf("ptr : %p, ", &insertnode)
		dummyhead.AddNode(insertnode)
	}
	fmt.Println()

	for now := dummytail.Prev; now != nil && now != &dummyhead; {
		fmt.Printf("%d ", now.val)
		now = now.Prev
	}
}


下面是指针传递

package main

import (
	"fmt"
	"math/rand"
)

type Node struct {
	val int
	Prev *Node
	Next *Node
}

func (node *Node) AddNode(nodeptr *Node) {
	nextptr := node.Next
	prevptr := node
	nextptr.Prev = nodeptr
	prevptr.Next = nodeptr
	nodeptr.Next = nextptr
	nodeptr.Prev = prevptr
}

func main() {
	dummyhead, dummytail := Node{val : -1}, Node{val: -1}
	dummyhead.Next = &dummytail
	dummytail.Prev = &dummyhead

	for i := 0; i < 10; i++ {
		randint := rand.Int() % 100
		fmt.Printf("%d ", randint)
		insertnode := &Node{val : randint}
		dummyhead.AddNode(insertnode)
	}
	fmt.Println()

	for now := dummytail.Prev; now != &dummyhead; {
		fmt.Printf("%d ", now.val)
		now = now.Prev
	}
}


值传递 是常见另外的结构体


1.4、方法/普通函数指针传递和方法指针传递区别


普通指针传递 和 方法指针传递区别

下面有例子 可以很明显发现有差别 方法相比普通函数 更像c++有类的感觉 而且最主要的是 不仅可以通过指针传递 还可以通过结构体传递 很方便
相反则不行了

package main

type Node struct {
	val int
	Prev *Node
	Next *Node
}

func (node *Node) FuncPtrAdd(addnum int) {
	node.val += addnum
}

func FuncAdd(node* Node, addnum int) {
	node.val += addnum
}

func main() {
	dummynode := Node{val : 0}
	nodeptr := &dummynode
	
	FuncAdd(nodeptr, 10)
	nodeptr.FuncPtrAdd(10)
	dummynode.FuncPtrAdd(10)
}


2.1、接口/方法签名集合


看了看接口 刚开始没看懂 之后才理解
接口内部类似定义了方法的捆绑题 相同的函数名方法 我们是可以声明给不同的结构体或者结构体指针的

接口的话 我们可以捆绑到不同的对象/结构体 然后使用接口的话 主要利用接口内部的方法 我们可以调用接口内部的方法

用一个我自己理解的例子吧 可以把接口当作通用模型
模型可以套在多个不同的对象上 只要兼容对象 然后这个模型我们能使用的是内部提供的通用方法


简单定义接口的定义的是
type interfacename interface { }

下面是大概写了两个结构体 大概表示了一下上面接口的用途
看名字确实也能明白是啥意思

package main

import (
	"fmt"
)

type GeneralInterface interface {
	Val() int
	Vaild() bool
}

type Node struct {
	key int
	val int
	end bool
}

func (node *Node) Val() int {
	return node.val
}

func (node *Node) Vaild() bool {
	return node.end
}

func (node *Node) TestVaild() bool {
	return node.end
}

type tmpstruct struct {
	val int
	vaild bool
}

func (ptr *tmpstruct) Val() int {
	return ptr.val
}

func (ptr *tmpstruct) Vaild() bool {
	return ptr.vaild
}

func (ptr *tmpstruct) Gogo() bool {
	return ptr.vaild
}

func main() {
	var g_interface GeneralInterface
	g_interface = &Node{1, 1, false}
	fmt.Println(g_interface.Val(), g_interface.Vaild())

	g_interface = &tmpstruct{2, true}
	fmt.Println(g_interface.Val(), g_interface.Vaild())
}

2.2、接口/接口断言


判断底层接口实际存储的类型 且断言可以防止恐慌 如果断言返回的有两个值 如果底层类型和我们的断言不相同 则不会引起恐慌


下面是测试结果

package main

import "fmt"

func main() {
	var g_interface interface{} = "hello"

	s1, ok1 := g_interface.(int)
	fmt.Println(s1, ok1)

	s2, ok2 := g_interface.(string)
	fmt.Println(s2, ok2)

	s3, ok3 := g_interface.(float64)
	fmt.Println(s3, ok3)

	s4 := g_interface.(int) // 报错(panic)
	fmt.Println(s4)
}


运行效果
在这里插入图片描述


2.3、接口/switch case


interface.(type)

只针对switch case
下面是例子


package main

import "fmt"

func main() {
	var g_interface interface{} = "hello"

	switch s := g_interface.(type) {
	case int:
		fmt.Println("int type,", "value:", s)
	case float64:
		fmt.Println("float64 type,", "value:", s)
	case float32:
		fmt.Println("float32 type,", "value:", s)
	default:
		fmt.Println("other type,", "value:", s)
	}
}


在这里插入图片描述


练习题、接口/stringer实现字符串打印


****

通常对于fmt包 内部会调用接口Stringer String 只要我们实现了接口对应的函数 就会调用我们这边的String 之后对于我们自定义的类 我就可以去定义这样的类了


示例代码

package main

import "fmt"

type IPAddr [4]byte

// TODO: 给 IPAddr 添加一个 "String() string" 方法

func main() {
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for name, ip := range hosts {
		fmt.Printf("%v: %v\n", name, ip)
	}
}

实现代码

package main

import (
	"fmt"
)

type IPAddr [4]byte

type Stringer interface {
	String() string
}

func (ptr IPAddr) String() string {
	return fmt.Sprintf("%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3])
}

func main() {
	hosts := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for name, ip := range hosts {
		fmt.Println(name, ip)
	}
}

实现效果
在这里插入图片描述


2.4、接口/错误


内部输出打印的时候 都采用的接口的方式
对应结构体字符串打印化 是采用的String() string
而对应错误打印的话 则是采用的Error() string

下面是简单的尝试了一下

package main

import (
	"fmt"
	"time"
)

type MyError struct {
	When time.Time
	Errstring string
}

func (error MyError) Error() string {
	return fmt.Sprintf("%v, %s", error.When, error.Errstring)
}

func RunError() error {
	return MyError{time.Now(), "Error Occur!"}
}

func main() {
	if err := RunError(); err != nil {
		fmt.Println(err)
	}
}

实现效果
在这里插入图片描述

======================
后续还有一些 就不写了
都是其他的接口练习 有兴趣的可以尝试一下

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

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

相关文章

机器学习5数据归一化Feature Scaling

文章目录一、为什么要数据归一化&#xff1f;二、解决方案数据归一化&#xff0c;解决方案1&#xff1a;最值归一化normalization&#xff1a;解决方案2&#xff1a;均值方差归一化standardization;三、最值归一化处理normalization四、均值方差归一化Standardization一、为什么…

ICMP协议(3层网络层协议:IP、ARP、ICMP)

1、ICMP协议端口号&#xff1f; 没有端口号&#xff0c;向TCP/UDP这些都是没有端口号只有协议号&#xff0c;只有应用层才有端口号。 2、ICMP协议是干什么的&#xff1f; 网络探测与回馈机制 1&#xff09;网络探测 2&#xff09;路由跟踪&#xff0c;windows命令&#xff1a;…

ABP:内置logger and 第三方库serilog 之间的关系

今天在看项目的日志记录功能&#xff0c;比较疑惑为什么项目中有的地方使用 Logger< T > _logger 然后又在资源文件下看见日志的第三方库 Serilog 解答&#xff1a; ASP.NET Core Build-in Logging ASP.NET Core 提供了 Logging 的抽象接口, third party 都会依据抽象来…

DJ 12-3 程序控制指令

目录 1. 无条件转移指令 JMP &#xff08;1&#xff09;段内直接转移 &#xff08;2&#xff09;段内间接转移 &#xff08;3&#xff09;段间直接转移 &#xff08;4&#xff09;段间间接转移 2. 条件转移指令 3. 循环控制指令 &#xff08;1&#xff09;LOOP 指令 &…

R语言中不同类型的聚类方法比较

聚类方法用于识别从营销&#xff0c;生物医学和地理空间等领域收集的多变量数据集中的相似对象。我们围绕聚类技术进行一些咨询&#xff0c;帮助客户解决独特的业务问题。它们是不同类型的聚类方法&#xff0c;包括&#xff1a; 划分方法分层聚类模糊聚类基于密度的聚类基于模…

Qt Creator 的 Shadow build(影子构建)

目录 一、什么是影子构建 二、如何取消影子构建 一、什么是影子构建 做wpf项目时&#xff0c;项目里面会有bin文件夹&#xff0c;里面有debug和release文件夹&#xff0c;生成的exe就在debug或release里面&#xff0c;但第一次做qt时&#xff0c;发现项目文件夹里面只有源码文…

2022 JuiceFS 社区用户调研结果出炉

为了使 JuiceFS 的发展更贴合用户的真实需求&#xff0c;我们在三周前向社区发出了一份调研问卷。此次调研面向已经将 JuiceFS 应用于生产环境的用户&#xff0c;了解其在应用 JuiceFS 前和使用中的体验与评价。 参与此次调研的用户&#xff0c;大型企业占比最高&#xff0c;有…

李炎恢ECMAScript6 / ES6+(一)

01. ECMAScript6 简介和历史 学习要点&#xff1a; 1.ES6 简介 2.ECMAScript 历史 3.学习和创建 Demo 本节课我们来开始了解 ECMAScript6(简称 ES6)&#xff0c;着重了解它的标准和历史。 一&#xff0e;ES6 简介 ECMAScript6 简称 ES6&#xff0c;是 JavaScript 语言的下一…

Vue3项目引入 vue-quill 编辑器组件并封装使用

这是一款支持Vue3的富文本编辑器 GitHub地址&#xff1a;https://github.com/vueup/vue-quill/ VueQuill官网&#xff1a;https://vueup.github.io/vue-quill/ // 查看 vueup/vue-quill 版本 npm view vueup/vue-quill versions --json// 导入 vueup/vue-quill 依赖包 npm i v…

试编写算法(用C语言)打印值为x的结点的所有祖先,假设值为x的结点不多于一个。(递归实现和非递归实现)

&#xff08;一&#xff09;递归实现&#xff1a; 完整代码&#xff1a; #include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std;#define MaxSize 100 typedef int ElemType; typedef struct BiNode {ElemType data;BiNode* lchil…

基于springboot摄影跟拍预定管理系统设计与实现的源码+文档

摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。…

最新版k8s 1.25版本安装

简介 Kubernetes&#xff08;k8s&#xff09;是自动化容器操作的开源平台。这些容器操作包括&#xff1a;部署、调度和节点集群间扩展。 具体功能&#xff1a; 自动化容器部署和复制。实时弹性收缩容器规模。容器编排成组&#xff0c;并提供容器间的负载均衡。 总而言之&…

PHP基于thinkphp的教材管理系统#毕业设计

教材是每个学生和学校都必须具备的教学资源之一,它是知识的载体,是学生汲取知识的土壤,好的教材可以做到事半功倍的效果。但是通常情况下教材都是批量进行购买和发放的,为了能够更好的对教材信息进行管理,我们通过PHP语言,thinkphp框架开发了本次的教材管理系统 教材管理系统,…

谷粒学苑_第十一天

要开始做前台部分(用户环境) 之前我们用的后台前端框架是vue-admin-template 这次的前台框架是用的NUXT 轮播图实现 显示课程和老师 redis缓存 NUXT 服务端渲染技术 解压guli_site 在这里我们使用的是成品,页面也基本写好 然后下载依赖: 开始运行: npm rum dev后面…

[附源码]Python计算机毕业设计Django高校车辆管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

力扣(LeetCode)123. 买卖股票的最佳时机 III(C++)

前后缀分解 维护前缀和数组&#xff0c;保存 111~iii 天&#xff0c;买卖一次的最大利润。维护后缀和数组&#xff0c;保存 iii~nnn 天买卖一次的最大利润。枚举所有分界点 iii &#xff0c;买卖两次的最大利润 iii 的前缀和 i\ i i 的后缀和 111~iii 天买卖一次的最大利润 i\…

Mock测试

1、什么是mock测试 Mock 测试就是在测试活动中&#xff0c;对于某些不容易构造或者不容易获取的数据/场景&#xff0c;用一个Mock对象来创建以便测试的测试方法。 2、Mock测试常见场景 &#xff08;1&#xff09;无法控制第三方系统接口的返回&#xff0c;返回的数据不满足要…

Tomcat的安装、在idea中的使用以及创建Web项目

目录Tomcat的安装Tomcat运行Tomcat在idea中的使用创建Web项目最后Tomcat的安装 Tomcat的官网: https://tomcat.apache.org/ 从官网上可以下载对应的版本进行使用。 下载windows64位&#xff0c;版本自行选择。 下载好之后找到压缩包进行解压&#xff0c;注意目录不要有中文且…

MFC文件操作

MFC提供了一个文件操作的基类CFile&#xff0c;这个类提供了一个没有缓存的二进制格式的磁盘输入输出功能。通过他的派生类可以间接的支持文本、文件、内存文件等。 打开文件 通过对CFile类的初始化&#xff0c;即可完成文件的打开 CFile类的其中一个构造函数&#xff1a; …

【论文精读】A Survey on Deep Learning for Named Entity Recognition

A Survey on Deep Learning for Named Entity Recognition前言Abstract1. INTRODUCTION2. BACKGROUND2.1 What is NER?2.2 NER Resources: Datasets and Tools2.3 NER Evaluation Metrics2.3.1 Exact-Match Evaluation2.3.2 Relaxed-Match Evaluation2.4 Traditional Approach…