Go语言学习笔记(五)

ops/2025/3/1 21:36:17/

文章目录

  • 十八、go操作MySQL、Redis
    • MySQL
    • Redis
  • 十九、泛型
    • 泛型函数
    • 泛型类型
    • 泛型约束
    • 泛型特化
    • 泛型接口
  • 二十、workspaces
    • 核心概念
    • 示例
  • 二十一、模糊测试

十八、go操作MySQL、Redis

MySQL

package mainimport ("database/sql""errors""fmt"_ "github.com/go-sql-driver/mysql""log""time"
)type User struct {UserId   int    `db:"id"`Username string `db:"name"`Phone    string `db:"phone"`Email    string `db:"email"`IdCard   string `db:"id_card"`
}var DB *sql.DBfunc init() {db, err := sql.Open("mysql", "root:123456@tcp(localhost:3306)/springbootclass")if err != nil {panic(err)}//最大空闲连接数,默认不配置,是2个最大空闲连接db.SetMaxIdleConns(5)//最大连接数,默认不配置,是不限制最大连接数db.SetMaxOpenConns(100)// 连接最大存活时间db.SetConnMaxLifetime(time.Minute * 3)//空闲连接最大存活时间db.SetConnMaxIdleTime(time.Minute * 1)err = db.Ping()if err != nil {log.Println("数据库连接失败")db.Close()panic(err)}DB = db}
func query(id int) (*User, error) {rows, err := DB.Query("select * from user where id=? limit 1", id)if err != nil {log.Println("执行sql语句出错")panic(err)}user := new(User)for rows.Next() {if err := rows.Scan(&user.UserId, &user.Username, &user.Phone, &user.Email, &user.IdCard); err != nil {log.Println("scan error:", err)return nil, errors.New(err.Error())}}return user, nil}
func save() {r, err := DB.Exec("insert into user (name,phone,email) values(?,?,?)", "test001", "man", "001@test.com")if err != nil {log.Println("执行sql语句出错")panic(err)}id, err := r.LastInsertId()if err != nil {log.Println("数据库无法连接")panic(err)}fmt.Println("插入成功:", id)
}func update(username string, id int) {ret, err := DB.Exec("update user set username=? where user_id=?", username, id)if err != nil {log.Println("更新出现问题:", err)return}affected, _ := ret.RowsAffected()fmt.Println("更新成功的行数:", affected)
}
func delete(id int) {ret, err := DB.Exec("delete from user where user_id=?", id)if err != nil {log.Println("删除出现问题:", err)return}affected, _ := ret.RowsAffected()fmt.Println("删除成功的行数:", affected)
}
func insertTx(username string) {tx, err := DB.Begin()if err != nil {log.Println("开启事务错误:", err)return}ret, err := tx.Exec("insert into user (username,sex,email) values (?,?,?)", username, "man", "test@test.com")if err != nil {log.Println("事务sql执行出错:", err)return}id, _ := ret.LastInsertId()fmt.Println("插入成功:", id)if username == "lisi" {fmt.Println("回滚...")_ = tx.Rollback()} else {_ = tx.Commit()}}
func main() {defer DB.Close()//save()query(14)
}

Redis

安装:go get github.com/go-redis/redis/v8

package mainimport ("context""fmt""github.com/go-redis/redis/v8"
)func main()  {ctx := context.Background()rdb := redis.NewClient(&redis.Options{Addr:	  "localhost:6379",Password: "", // no password setDB:		  0,  // use default DB})err := rdb.Set(ctx, "key", "value", 0).Err()if err != nil {panic(err)}val, err := rdb.Get(ctx, "key").Result()if err != nil {panic(err)}fmt.Println("key", val)val2, err := rdb.Get(ctx, "key2").Result()if err == redis.Nil {fmt.Println("key2 does not exist")} else if err != nil {panic(err)} else {fmt.Println("key2", val2)}
}

十九、泛型

泛型(Generics)是一种编程思想,它允许在编写代码时使用未知的类型。泛型可以增加代码的灵活性和可复用性,同时还能提高代码的安全性和可读性。泛型在 C++, Java 和 Python 等语言中已经被广泛应用,但在 Go 中一直未被支持。

Go 1.18 版本终于加入了泛型特性,这一特性的引入被认为是 Go 语言历史上的一件大事。

详细文档:Tutorial: Getting started with generics - The Go Programming Language

示例:

package mainimport "fmt"// // SumInts adds together the values of m.
//
//	func SumInts(m map[string]int64) int64 {
//		var s int64
//		for _, v := range m {
//			s += v
//		}
//		return s
//	}
//
// // SumFloats adds together the values of m.
//
//	func SumFloats(m map[string]float64) float64 {
//		var s float64
//		for _, v := range m {
//			s += v
//		}
//		return s
//	}
//
// SumIntsOrFloats sums the values of map m. It supports both int64 and float64
// as types for map values.
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {var s Vfor _, v := range m {s += v}return s
}
func main() {// Initialize a map for the integer valuesints := map[string]int64{"first":  34,"second": 12,}// Initialize a map for the float valuesfloats := map[string]float64{"first":  35.98,"second": 26.99,}fmt.Printf("Non-Generic Sums: %v and %v\n",//SumInts(ints),//SumFloats(floats))SumIntsOrFloats(ints),SumIntsOrFloats(floats))
}

泛型函数

在 Golang 中,泛型的语法包括类型参数、类型约束、泛型函数和泛型类型等。

在 Go 中,泛型函数的语法如下:

 func FuncName[T Type](params) returnType {// Function body}

其中,T 表示泛型类型参数,Type 表示具体的类型,params 表示函数的参数,returnType 表示函数的返回值类型。

泛型类型

除了泛型函数之外,Go 1.18 版本还引入了泛型类型。泛型类型的语法如下:

 type TypeName[T Type] struct {// Fields}

其中,TypeName 表示泛型类型名称,T 表示泛型类型参数,Type 表示具体的类型。

泛型约束

在使用泛型时,有时需要对泛型类型进行一定的约束。例如,我们希望某个泛型函数或类型只能接受特定类型的参数,或者特定类型的参数必须实现某个接口。在 Go 中,可以使用泛型约束来实现这些需求

类型约束可以让泛型函数或类型只接受特定类型的参数。在 Go 中,类型约束可以使用 interface{} 类型和类型断言来实现。

类型约束可以使用在类型参数后加上一个约束类型来实现。

除了使用 interface{} 类型进行类型约束之外,Go 还支持使用接口来约束泛型类型。

泛型特化

泛型特化是指将泛型代码转换为具体类型的代码。在 Go 中,泛型特化是在编译期间完成的。特化可以提高代码的性能和运行效率,因为编译器可以针对具体类型进行优化,避免了运行时的类型检查和类型转换。

在 Go 中,泛型特化是通过代码生成器实现的。代码生成器会根据泛型类型或函数的定义,生成具体类型或函数的代码。例如,下面是一个泛型函数的定义:

css 代码解读复制代码 func Swap[T any](a, b *T) {*a, *b = *b, *a}

该函数可以交换任意类型的两个变量的值。在编译期间,代码生成器会根据调用该函数时传递的参数类型生成具体的函数代码。例如,如果传递的是整数类型的指针,代码生成器会生成以下代码:

css 代码解读复制代码 func Swap_int(a, b *int) {*a, *b = *b, *a}

如果传递的是字符串类型的指针,代码生成器会生成以下代码:

css 代码解读复制代码 func Swap_string(a, b *string) {*a, *b = *b, *a}

泛型接口

泛型接口是一种可以处理多种类型数据的接口。在 Golang 中,可以使用类型参数来实现泛型接口。

二十、workspaces

Go 多模块工作区能够使开发者能够更容易地同时处理多个模块的工作,如:

方便进行依赖的代码调试(打断点、修改代码)、排查依赖代码 bug
方便同时进行多个仓库/模块并行开发调试

Tutorial: Getting started with multi-module workspaces - The Go Programming Language

go 使用的是多模块工作区,可以让开发者更容易同时处理多个模块的开发。在 Go 1.17 之前,只能使用 go.mod replace 指令来实现,如果你正巧是同时进行多个模块的开发,使用它可能是很痛苦的。每次当你想要提交代码的时候,都不得不删除掉 go.mod 中的 replace 才能使模块稳定的发布版本。•在使用 go 1.18 多模块工作区功能的时候,就使用这项工作变得简单容易处理。下面我来介绍怎么使用这一功能。•Go 多模块工作区文档、代码示例[5]

核心概念

在 Go 中,工作区(workspace)是由一个包含多个 Go 模块的目录结构构成的,主要用于管理依赖关系、构建过程以及代码模块的交互。

一个 Go 工作区通常由以下部分组成:

  • 多个模块:每个模块都有自己的 go.mod 文件,定义了该模块的依赖、版本等。
  • 共享的 go.work 文件:在 Go 1.18 引入的 go.work 文件中,指定了多个 Go 模块的位置,Go 工具链通过这个文件了解工作区的所有模块,并能处理模块间的依赖。

go.work 文件是工作区的核心,类似于 go.mod 文件,但它不是用来定义单个模块的依赖,而是用来定义多个模块如何协作、如何管理工作区中的依赖关系。通过这个文件,Go 工具链知道工作区内所有模块的位置,并且能够更好地进行依赖解析和构建。

go.work 文件的基本结构

goCopyEditgo 1.18use (./module1./module2
)
  • go 1.18:指定 Go 的版本。
  • use:指定工作区中的模块位置。每个模块路径指向一个相对路径或 Git 仓库。

示例

创建工作区

  1. 创建一个新的目录作为工作区。
  2. 在工作区中初始化多个 Go 模块(每个模块都有独立的 go.mod)。
  3. 创建 go.work 文件并将模块添加到该文件中。

示例

  1. 创建一个工作区目录 myworkspace,并在其中创建两个模块:

    mkdir myworkspace
    cd myworkspace
    go mod init module1
    cd ..
    go mod init module2
    
  2. 创建 go.work 文件来定义工作区:

    go work init ./module1 ./module2
    

    这样就创建了一个包含 module1module2 的工作区,go.work 文件会自动更新,指示 Go 工具链知道这些模块是工作区的一部分。

二十一、模糊测试

Go 1.18在go工具链里引入了fuzzing模糊测试,可以帮助我们发现Go代码里的漏洞或者可能导致程序崩溃的输入。

参考文章:Tutorial: Getting started with fuzzing - The Go Programming Language

package mainimport "fmt"func Reverse(s string) string {fmt.Printf("input: %q\n", s)r := []rune(s)fmt.Printf("runes: %q\n", r)for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {r[i], r[j] = r[j], r[i]}return string(r)
}
func main() {input := "The quick brown fox jumped over the lazy dog"rev := Reverse(input)doubleRev := Reverse(rev)fmt.Printf("original: %q\n", input)fmt.Printf("reversed: %q\n", rev)fmt.Printf("reversed again: %q\n", doubleRev)
}

fuzzing的优点之一是可以基于开发者代码里指定的测试输入作为基础数据,进一步自动生成新的随机测试数据,用来发现指定测试输入没有覆盖到的边界情况。

在单元测试里,因为测试输入是固定的,你可以知道调用Reverse函数后每个输入字符串得到的反转字符串应该是什么,然后在单元测试的代码里判断Reverse的执行结果是否和预期相符。例如,对于测试用例Reverse("Hello, world"),单元测试预期的结果是 "dlrow ,olleH"

但是使用fuzzing时,我们没办法预期输出结果是什么,因为测试的输入除了我们代码里指定的用例之外,还有fuzzing随机生成的。对于随机生成的测试输入,我们当然没办法提前知道输出结果是什么。

虽然如此,本文里的Reverse函数有几个特性我们还是可以在模糊测试里做验证。

  1. 对一个字符串做2次反转,得到的结果和源字符串相同
  2. 反转后的字符串也仍然是一个有效的UTF-8编码的字符串

注意:fuzzing模糊测试和Go已有的单元测试以及性能测试框架是互为补充的,并不是替代关系。

参考文章:官方教程:Go fuzzing模糊测试 - 知乎 (zhihu.com)


http://www.ppmy.cn/ops/162333.html

相关文章

关于手眼标定的数学模型及标定流程

手眼标定介绍 在手眼标定中&#xff0c;AXXB和AXYB是两种常见的数学模型&#xff0c;用于描述相机和机械臂之间的关系。 手眼标定中的两种情况&#xff1a;眼在手上&#xff08;Eye-in-Hand&#xff09;和眼在手外&#xff08;Eye-to-Hand&#xff09; 求解略有不同&#xff…

【AI+智造】在阿里云Ubuntu 24.04上部署DeepSeek R1 14B的完整方案

作者&#xff1a;Odoo技术开发/资深信息化负责人 日期&#xff1a;2025年2月28日 一、部署背景与目标 DeepSeek R1作为国产大语言模型的代表&#xff0c;凭借其强化学习驱动的推理能力&#xff0c;在复杂任务&#xff08;如数学问题、编程逻辑&#xff09;中表现优异。本地化部…

使用Docker Compose部署 MySQL8

MySQL 8 是一个功能强大的关系型数据库管理系统,而 Docker 则是一个流行的容器化平台。结合使用它们可以极大地简化 MySQL 8 的部署过程,并且确保开发环境和生产环境的一致性。 安装 Docker 和 Docker Compose 首先,确保你的机器上已经安装了 Docker 和 Docker Compose。 …

《OpenCV》——实例:答题卡识别

答题卡识别 实例内容&#xff1a; 该实例实现了一个基于计算机视觉技术的答题卡自动识别与评分系统&#xff0c;利用 OpenCV 库对答题卡图像进行处理和分析&#xff0c;最终得出答题卡的得分。 实例步骤&#xff1a; 导入必要的库 import numpy as np import cv2导入num…

1.2 Kaggle大白话:Eedi竞赛Transformer框架解决方案02-GPT_4o生成训练集缺失数据

目录 0. 本栏目竞赛汇总表1. 本文主旨2. AI工程架构3. 数据预处理模块3.1 配置数据路径和处理参数3.2 配置API参数3.3 配置输出路径 4. AI并行处理模块4.1 定义LLM客户端类4.2 定义数据处理函数4.3 定义JSON保存函数4.4 定义数据分片函数4.5 定义分片处理函数4.5 定义文件名排序…

DeepSeek开源周Day2:DeepEP - 专为 MoE 模型设计的超高效 GPU 通信库

项目地址&#xff1a;https://github.com/deepseek-ai/DeepEP 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (2/5)&#xff01; ​ ​ 引言 在大模型训练中&#xff0c;混合专家模型&#xff08;Mixture-of-Experts, MoE&#xff09;因其动…

AI关于SHAP分析与列线图(算法)解释线性模型矛盾之处的解释

AI关于SHAP分析与列线图&#xff08;算法&#xff09;解释线性模型矛盾之处的解释 两种解释方法在个案的局部解释方面&#xff0c;有矛盾之处&#xff0c;其背后的原理已经超出了我的知识范畴&#xff0c;以下是询问AI的几个问题&#xff0c;希望能从中梳理出一个合理的解释。…

HTTP 动态报错码的原因和解决方法

目录 1xx&#xff08;信息性状态码&#xff09; 2xx&#xff08;成功状态码&#xff09; 3xx&#xff08;重定向状态码&#xff09; 4xx&#xff08;客户端错误状态码&#xff09; 5xx&#xff08;服务器错误状态码&#xff09; 参考文章 以下是 HTTP 动态报错码的常见原…