当前位置: 首页 > news >正文

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)}
}

注意理解具体执行过程:

  1. run() 返回一个 error 接口值,其动态类型为 *MyError,动态值为 &MyError{}

  2. 当执行

    fmt.Println(err)
    

    时:

    • err.Error() 被隐式调用。
    • 动态类型 *MyErrorError() 方法被执行,返回一个字符串。

错误包装

其实很好理解,就是使用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/*

示例代码:

image-20241122201153813

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。例如&#xff0c…...

js的简单介绍

一.javascript(是什么) 是一种运行在客户端(浏览器)的编程语言,实现人机交互效果 作用 网页特效(监听客户的一些行为让网页做出对应的反馈)表单验证(针对表格数据的合法性进行判断)数据交互(获取后台的数据&#xf…...

神经网络 - 激活函数(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,能装下的最大价值 递推公式&#xff1…...

安装 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.在注册登录的练习里面&#xff0c;追加一个QListWidget项目列表 要求:点击注册之后&#xff0c;将账号显示到列表窗口小部件上面去 以及&#xff0c;在列表窗口小部件中双击某个账号的时候&#xff0c;将该账号删除 头文件 #ifndef WIDGET_H #define WIDGET_H #include <…...

版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点

版图自动化连接算法开发 00001 ------ 直接连接两个给定的坐标点 引言正文定义坐标点的类绘图显示代码直接连接两个坐标点引言 由于人工智能的加速普及,每次手动绘制版图都会觉得特别繁琐,作者本人在想可否搞一个自动化连接器件端口的算法,后期可以根据一些设定的限制进行避…...

迷你世界脚本方块接口:Block

方块接口&#xff1a;Block 彼得兔 更新时间: 2024-08-27 11:04:56 具体函数名及描述如下&#xff1a; 序号 函数名 函数描述 1 isSolidBlock(...) 是否是固体方块 2 isLiquidBlock(...) 是否是液体方块 3 isAirBlock(...) 是否是气体方块 4 getBl…...

打造高清3D虚拟世界|零基础学习Unity HDRP高清渲染管线(第一天)

打造高清3D虚拟世界|零基础学习Unity HDRP高清渲染管线&#xff08;第一天&#xff09; 前言最后 前言 说真的&#xff0c;用Unity工作这几年&#xff0c;经历的项目大大小小&#xff0c;对于场景的渲染算是有一定的经验&#xff0c;但涉及到HDRP高清渲染管线的了解&#xff0…...

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 的详细对比&#xff0c;涵盖设计目标、核心功能、性能、适用场景及优劣势分析&#xff1a; 1. 核心定位与设计目标 维度WeaviateChromaDB类型向量数据库 图数据库&#xff08;支持混合搜索&#xff09;轻量级纯向量数据库&#xff08;专注嵌入存…...

2024华为OD机试真题-热点网站统计(C++)-E卷-100分

2024华为OD机试最新E卷题库-(C卷+D卷+E卷)-(JAVA、Python、C++) 目录 题目描述 输入描述 输出描述 用例1 用例2 考点 题目解析 代码 c++ 题目描述 企业路由器的统计页面,有一个功能需要动态统计公司访问最多的网页 URL top N。 请设计一个算法,可以高效动态统计 …...

【大模型】大模型分类

大模型&#xff08;Large Models&#xff09;通常指参数量巨大、计算能力强大的机器学习模型&#xff0c;尤其在自然语言处理&#xff08;NLP&#xff09;、计算机视觉&#xff08;CV&#xff09;等领域表现突出。以下是大模型的常见分类方式&#xff1a; 1. 按应用领域分类 …...

Redis 的几个热点知识

前言 Redis 是一款内存级的数据库&#xff0c;凭借其卓越的性能&#xff0c;几乎成为每位开发者的标配工具。 虽然 Redis 包含大量需要掌握的知识&#xff0c;但其中的热点知识并不多。今天&#xff0c;『知行』就和大家分享一些 Redis 中的热点知识。 Redis 数据结构 Redis…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...

开疆智能Ethernet/IP转Modbus网关连接鸣志步进电机驱动器配置案例

在工业自动化控制系统中&#xff0c;常常会遇到不同品牌和通信协议的设备需要协同工作的情况。本案例中&#xff0c;客户现场采用了 罗克韦尔PLC&#xff0c;但需要控制的变频器仅支持 ModbusRTU 协议。为了实现PLC 对变频器的有效控制与监控&#xff0c;引入了开疆智能Etherne…...