Go红队开发—语法补充
文章目录
- 错误控制
- 使用
- 自定义错误类型
- 错误包装
- errors.Is 和 errors.As
- panic捕获、recover 、defer
- 错误控制练习
- 接口
- 结构体实现接口
- 基本类型实现接口
- 切片实现接口
- 接口练习
- Embed嵌入文件
之前有师傅问这个系列好像跟红队没啥关系,前几期确实没啥关系,因为这都是进行红队工具开发的前置知识点,对于我个人强迫症而言只是想让这个系列更加完善而已,所以前置知识也加进去了,有GO知识的大佬可以等下一期哈!感谢支持。
错误控制
使用
1. errors.New("错误信息") //这个属于error类型
例子://你会看到error返回类型,return 0, errors.New("除数不能为零")
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("除数不能为零") }
return a / b, nil
}2.fmt.Errorf:错误包装,后面会详细讲。这个函数允许你使用格式化字符串创建错误,类似于 fmt.Sprintf。
这个没啥好说的,只是说New的时候只能是字符串,而你用这个就能够格式化字符串,将变量放在里面格式化输出在错误中。
err := fmt.Errorf("invalid argument: %v", value)3.errors.Is:判断错误链中是否包含该错误
if errors.Is(err, myError) {// err 是 myError自定义
}
自定义错误类型
自定义错误类型:通过实现 error 接口来自定义错误类型。
示例代码:
package mainimport "fmt"type MyError struct {When stringWhat string
}func (e *MyError) Error() string {return fmt.Sprintf("在 %s 发生 %s ", e.When, e.What)
}
func run() error {return &MyError{When: "运行时",What: "错误1",}
}
func main() {err := run()if err != nil {fmt.Println(err)}
}
注意理解具体执行过程:
-
run()返回一个error接口值,其动态类型为*MyError,动态值为&MyError{}。 -
当执行
fmt.Println(err)时:
err.Error()被隐式调用。- 动态类型
*MyError的Error()方法被执行,返回一个字符串。
错误包装
其实很好理解,就是使用fmt.Errorf("获取数据失败: %w", err),这相当于用获取数据失败:这个字符串包了一下err
所以fmt.Errorf("获取数据失败: %w", err)解包的时候就是等于err,因为后面的Is(is)就是为啥能判断错误链里是否包含的。
package mainimport ("errors""fmt"
)// 定义一个自定义错误
var ErrNotFound = errors.New("资源未找到")func fetchData(id int) error {if id == 0 {return ErrNotFound // 返回原始错误}return nil
}func main() {// 调用 fetchData 并包装错误err := fetchData(0)if err != nil {// 使用 fmt.Errorf 包装原始错误,添加上下文wrappedErr := fmt.Errorf("获取数据失败: %w", err)fmt.Println(wrappedErr) // 打印包装后的错误信息// 检查包装的错误是否包含特定错误if errors.Is(wrappedErr, ErrNotFound) {fmt.Println("错误类型: 资源未找到")}// 解包原始错误unwrappedErr := errors.Unwrap(wrappedErr)fmt.Printf("解包后的错误: %v\n", unwrappedErr)}
}
输出如下:(看下面的输出就知道什么情况了)
获取数据失败: 资源未找到
错误类型: 资源未找到
解包后的错误: 资源未找到
errors.Is 和 errors.As
了解了错误包装之后就知道这两的区别了,Is就是判断错误链中是否包含你这个错误,只要包含一个即可。
As就是只判断当前的,不管你是否包含的。
package mainimport ("errors""fmt"
)var ErrDivideByZero = errors.New("除数不能为零")func divide(a, b int) (int, error) {if b == 0 {return 0, ErrDivideByZero}return a / b, nil
}
func main() {_, err := divide(4, 0)if errors.Is(err, ErrDivideByZero) { //可以是ErrDivideByZero错误的错误链,因为有可能是进行了错误包装fmt.Println("捕获到除以零的错误")} else {fmt.Println("其他错误:", err)}if errors.As(err, &ErrDivideByZero) { //一定要是ErrDivideByZero错误,同时要是一个指针,源码的painc写着target must be a non-nil pointerfmt.Println("捕获到除以零的错误")} else {fmt.Println("其他错误:", err)}
}
panic捕获、recover 、defer
解释:
panic能够改变程序的控制流,调用panic后会立刻停止执行当前函数的剩余代码,并在当前 Goroutine 中递归执行调用方的defer;recover可以中止panic造成的程序崩溃。它是一个只能在defer中发挥作用的函数,在其他作用域中调用不会发挥作用;
注意:recover 只能在 defer 函数中调⽤,并且只有在 panic 发⽣时才会返回⾮ nil 值。
//恐慌捕获 panic recover defer
func start_panic() {defer func() {//使用defer来等待后面panic执行一个panic后再进行捕获if r := recover(); r != nil {fmt.Println("捕获到了:", r)}}()panic("一个panic")
}func main() {fmt.Println("开始捕获panic")start_panic()fmt.Println("结束捕获panic")
}
错误控制练习
固定打开一个1.txt文件,然后使用自定义错误类型,同时进行panic捕获,输出预期:错误,非预期:错误
type FileNotFoundError struct {filename string
}func (f FileNotFoundError) Error() string {return fmt.Sprintf("文件 %s 不存在。", f.filename)
}func readfile(file_name string) (string, error) {//panic一下defer func() {if r := recover(); r != nil {fmt.Println("panic is ", r)}}()if file_name != "1.txt" {return "", FileNotFoundError{filename: file_name}}bytes, err := os.ReadFile("1.txt")if err != nil {return "", fmt.Errorf("文件 %s 打开出错", file_name)} else {return string(bytes), nil}
}func main() {file, err := readfile("1.txt")if err != nil {if errors.As(err, FileNotFoundError{}) {fmt.Println("预期错误:", err)} else {fmt.Println("非预期错误:", err)}return}fmt.Println("文件内容为:", file)
}
接口
接口在go语言中也有点抽象,对于接口的实现其实很简单,只是在用的时候比较抽象,结构体实现接口反而是最容易接受的,像基本类型还有切片这两种接口的使用就比较抽象。
结构体实现接口
(在结构体实现结构以及方法的调用基本没啥问题,很正常的操作)
package mainimport "fmt"type User interface {getName() stringgetAge() int
}type Person struct {name stringage int
}func (p Person) getName() string {return p.name
}
func (p Person) getAge() int {return p.age
}func main() {p := Person{name: "zhangsan",age: 18,}fmt.Println(p.getName(), p.getAge())
}
基本类型实现接口
这里我分两种情况,string和int实现接口,目的是了解在实现接口后怎么使用这个方法。
type Stringer interface {
//接口的这两个方法写了之后就要实现。所以下面就实现了String() stringAscii() string
}
type MyString string //string类型
type MyInt int //int类型func (s MyString) String() string {return string(s) //其实可以不转string也能直接返回,因为MyString本身就是string类型,只是我换了个别名而已
}
func (t MyInt) Ascii() string {return string(t) //一定要转,因为本身是int类型
}
func (t MyInt) String() string {return fmt.Sprintf("%d", t) //一定要转,因为本身是int类型
}func main() {//结构体实现接口效果//start_struct_interface()var s Stringer = MyString("传递参数string") var i Stringer = MyInt(97)fmt.Println(s.String())fmt.Println(i.Ascii()) //将数字转为asciifmt.Println(i.String()) //将数字作为字符串输出
}
细节:
实际操作下来其实也没有说很难理解,只是可能类型转换那个地方卡了一下导致难以理解而已
重点是看懂这里的代码:
var s Stringer = MyString("传递参数string")
var i Stringer = MyInt(97)
接口类型接收实现了接口方法的类型,然后就能够调用接口方法了,就这么理解就行了。在MyString和MyInt中都是强制类型转换,将string字符和int数字转为对应的别名,然后给到变量后就能直接使用实现了接口的方法,因为已经转为了那两个基本类型了。
在强调一遍:本身是没有我们定义的这种类型的,所以要强制转换,然后接口其实就能随便写了,管你要不要用他这个值。
条件:
属于这个类型(强制类型转换)
实现了接口方法(正常实现接口方法)
调用就直接调用即可(正常)
切片实现接口
其实到了切片实现接口就很容易理解了
我发现其实是你这个类型实现了这个接口后,就可以用了
我发现要用这个方法只是仅仅的需要你是这个类型,而不是说在于什么强制类型转换,而是你要用这个接口方法是因为那个类型实现了这个接口啊,所以你要强制类型转换,所以要实例化这个类型啊,确实有点悟道了,也有点不明白我之前到底为啥会卡住。
切片实现接口也很简单,到这里其实已经不分什么结构体、基本类型、切片的了,本质就是你实例化一个实现了接口的类型,然后你的某个类型实现了接口类型的方法,那么你就直接实例化给到接口类型就拿这个类型去调用方法就行了。 (有点抽象,还是直接看代码吧)
type I_slice interface { //接口类型sum() int //返回切片的和
}
type MySlice []int //切片类型,换一个intslice别名而已,方便自定义,且实现接口方法func (ms I_slice) sum() int { //就是自己定义的类型实现了接口类型而已,很好理解s := 0for _, v := range ms {s += v}return s
}func main() {var s I_slice = MySlice{1, 2, 3, 4, 5} //我们自己自定义的切片类型然后赋值给接口类型//var s MySlice = MySlice{1, 2, 3, 4, 5} //var s = MySlice{1, 2, 3, 4, 5} //这两其实也可以,就是我们自定义的类型本来就是有实现这个方法的,只不过你没有赋值给接口类型,所以不算实现了接口的方法而已,但是你本身就拥有的方法当然可以用啦fmt.Println(s.sum())
}
接口练习
项⽬描述
创建⼀个形状计算器,它可以计算不同形状的⾯积。需要定义⼀个 Shape 接⼝,
并为不同的形状(如圆形和矩形)实现这个接⼝。
然后编写⼀个函数来计算并打印这些形状的⾯积。 步骤
定义⼀个 Shape 接⼝,包含⼀个 area ⽅法。
创建⼀个 Circle 结构体,并实现 Shape 接⼝。
创建⼀个 Rectangle 结构体,并实现 Shape 接⼝。
编写⼀个函数 printArea,接受⼀个 Shape 类型的参数,并打印它的⾯积。
在 main 函数中创建⼀些 Circle 和 Rectangle 实例,并调⽤ printArea 函数来打印它们的⾯积。
示例代码
type Shape interface {Area() float64
}type Circle struct {radius float64
}type Rectangle struct {width float64height float64
}func (c Circle) Area() float64 {return (c.radius * c.radius * math.Pi)
}
func (r Rectangle) Area() float64 {return (r.width * r.height)
}func printArea(s Shape) {/*这里实际上就相当于强制类型转换了,因为两个结构体实现了Area方法,那么就强制类型转换为Shape后能够在函数中正常使用该方法*/fmt.Printf("%.2f\n", s.Area())
}
func main() {dc := Circle{radius: 2}r := Rectangle{width: 2, height: 4}printArea(c)printArea(r)
}
Embed嵌入文件
只支持嵌入为string, byte切片和embed.FS三种类型。相对来说比较难理解的是embed.FS。
使⽤//go:embed后,下⽅必须是全局变量。
使用embed可以嵌⼊⽂件夹下的⽂件,使⽤通配符*,比如static/*
示例代码:

package mainimport ("embed"_ "embed""fmt"
)//go:embed a.txt
var a string//go:embed static/1.txt
var s []byte//go:embed static/*
var f1 embed.FS//go:embed static/* static/2.txt
var f2 embed.FS//go:embed static/1.txt
//go:embed static/2.txt
//go:embed static/3.txt
var f3 embed.FSfunc main() {fmt.Println("============string接收================")fmt.Println(a)fmt.Println("============byte接收================")fmt.Printf("%q\n", s)fmt.Println(string(s))fmt.Println("============FS单个文件================")data, _ := f1.ReadFile("static/1.txt")fmt.Println(string(data))fmt.Println("============FS目录,当前目录等等多个文件,go:embed空格隔开================")data, _ = f2.ReadFile("static/2.txt")fmt.Println(string(data))fmt.Println("============FS多个文件,go:embed可以不用空格隔开================")data, _ = f3.ReadFile("static/3.txt")fmt.Println(string(data))
}
相关文章:
Go红队开发—语法补充
文章目录 错误控制使用自定义错误类型错误包装errors.Is 和 errors.Aspanic捕获、recover 、defer错误控制练习 接口结构体实现接口基本类型实现接口切片实现接口 接口练习Embed嵌入文件 之前有师傅问这个系列好像跟红队没啥关系,前几期确实没啥关系,因为…...
二、Redis 安装与基本配置:全平台安装指南 服务器配置详解
Redis 安装与基本配置:全平台安装指南 & 服务器配置详解 Redis 作为高性能的内存数据库,其安装和配置是使用 Redis 的第一步。本篇文章将全面介绍 Redis 的安装方式,覆盖 Windows、Linux、Docker 环境,并详细讲解 Redis 的基础配置,包括 持久化、日志、端口设置等。此…...
halcon学习笔记1
环境的搭建就不说了,主要是作者在入职后的实际学习与实践。 打开应用程序 这里作者的个人理解是1号区域主要是可以观察到读取的图像以及后续对图像进行何种操作,2的算子类似于Opencv中的API,可以在上面进行参数的调整,例如read_I…...
解决Docker拉取镜像超时错误,docker: Error response from daemon:
当使用docker pull或docker run时遇到net/http: request canceled while waiting for connection的报错,说明Docker客户端在访问Docker Hub时出现网络连接问题。可以不用挂加速器也能解决,linux不好用clash。以下是经过验证的方法(感谢轩辕镜…...
Masscan下载Linux安装
masscan 是一款高速的端口扫描工具,能够在极短的时间内扫描大量IP地址和端口。以下是关于如何在Linux系统上下载并安装 masscan 的详细步骤。 ### 通过包管理器安装 对于一些Linux发行版,你可以直接使用系统的包管理器来安装 masscan。例如,…...
js的简单介绍
一.javascript(是什么) 是一种运行在客户端(浏览器)的编程语言,实现人机交互效果 作用 网页特效(监听客户的一些行为让网页做出对应的反馈)表单验证(针对表格数据的合法性进行判断)数据交互(获取后台的数据…...
神经网络 - 激活函数(Swish函数、GELU函数)
一、Swish 函数 Swish 函数是一种较新的激活函数,由 Ramachandran 等人在 2017 年提出,其数学表达式通常为 其中 σ(x) 是 Sigmoid 函数(Logistic 函数)。 如何理解 Swish 函数 自门控特性 Swish 函数可以看作是对输入 x 进行“…...
关于后端使用Boolean或boolean时前端收到的参数的区别
当后端使用的是Boolean时,调用的方法是setIsLoginUser,前端收到的参数的参数名是isLoginUser 而当后端使用的是boolean时,调用的方法是setLoginUser,前端收到的参数的参数名是loginUser 封装类和基本数据类型在使用时需要注意这…...
笔记:代码随想录算法训练营第35天: 01背包问题 二维、 01背包问题 一维 、LeetCode416. 分割等和子集
学习资料:代码随想录 这一块儿学得挺痛苦 注:文中含大模型生成内容 动态规划:01背包理论基础 卡码网第46题 思路:五部曲 定义:dp[i][j]为第i个物品背包容量为j,能装下的最大价值 递推公式࿱…...
安装 Windows Docker Desktop - WSL问题
一、关联文章: 1、Docker Desktop 安装使用教程 2、家庭版 Windows 安装 Docker 没有 Hyper-V 问题 3、打开 Windows Docker Desktop 出现 Docker Engine Stopped 问题 二、问题解析 打开 Docker Desktop 出现问题,如下: Docker Desktop - WSL update failed An error o…...
Spring MVC 返回数据
目录 1、什么是 SpringMVC2、返回数据2.1、返回 JSON 对象2.2、请求转发2.3、请求重定向2.4、自定义返回的内容 1、什么是 SpringMVC 1、Tomcat 和 Servlet 分别是什么?有什么关系? Servlet 是 java 官方定义的 web 开发的标准规范;Tomcat 是…...
QT-信号与槽
1.在注册登录的练习里面,追加一个QListWidget项目列表 要求:点击注册之后,将账号显示到列表窗口小部件上面去 以及,在列表窗口小部件中双击某个账号的时候,将该账号删除 头文件 #ifndef WIDGET_H #define WIDGET_H #include <…...
版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点
版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点 引言正文定义坐标点的类绘图显示代码直接连接两个坐标点引言 由于人工智能的加速普及,每次手动绘制版图都会觉得特别繁琐,作者本人在想可否搞一个自动化连接器件端口的算法,后期可以根据一些设定的限制进行避…...
迷你世界脚本方块接口:Block
方块接口:Block 彼得兔 更新时间: 2024-08-27 11:04:56 具体函数名及描述如下: 序号 函数名 函数描述 1 isSolidBlock(...) 是否是固体方块 2 isLiquidBlock(...) 是否是液体方块 3 isAirBlock(...) 是否是气体方块 4 getBl…...
打造高清3D虚拟世界|零基础学习Unity HDRP高清渲染管线(第一天)
打造高清3D虚拟世界|零基础学习Unity HDRP高清渲染管线(第一天) 前言最后 前言 说真的,用Unity工作这几年,经历的项目大大小小,对于场景的渲染算是有一定的经验,但涉及到HDRP高清渲染管线的了解࿰…...
Docker项目部署-部署前端
nginx.conf文件内容如下。 worker_processes 1;events {worker_connections 1024; }http {include mime.types;default_type application/json;sendfile on;keepalive_timeout 65;server {listen 18080;# 指定前端项目所在的位置location / {root /usr/…...
【向量数据库Weaviate】与ChromaDB的差异、优劣
以下是 Weaviate 和 ChromaDB 的详细对比,涵盖设计目标、核心功能、性能、适用场景及优劣势分析: 1. 核心定位与设计目标 维度WeaviateChromaDB类型向量数据库 图数据库(支持混合搜索)轻量级纯向量数据库(专注嵌入存…...
2024华为OD机试真题-热点网站统计(C++)-E卷-100分
2024华为OD机试最新E卷题库-(C卷+D卷+E卷)-(JAVA、Python、C++) 目录 题目描述 输入描述 输出描述 用例1 用例2 考点 题目解析 代码 c++ 题目描述 企业路由器的统计页面,有一个功能需要动态统计公司访问最多的网页 URL top N。 请设计一个算法,可以高效动态统计 …...
【大模型】大模型分类
大模型(Large Models)通常指参数量巨大、计算能力强大的机器学习模型,尤其在自然语言处理(NLP)、计算机视觉(CV)等领域表现突出。以下是大模型的常见分类方式: 1. 按应用领域分类 …...
Redis 的几个热点知识
前言 Redis 是一款内存级的数据库,凭借其卓越的性能,几乎成为每位开发者的标配工具。 虽然 Redis 包含大量需要掌握的知识,但其中的热点知识并不多。今天,『知行』就和大家分享一些 Redis 中的热点知识。 Redis 数据结构 Redis…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
