Contexthelper优化
2024-4-4
| 2025-6-27
字数 2509阅读时长 7 分钟
Created time
Apr 3, 2024 06:52 AM
date
Apr 4, 2024
status
Published
category
技术分享
Origin
summary
tags
type
Post
URL
icon
password
slug
本文由 简悦 SimpRead 转码, 原文地址 vlog.jiejaitt.top
有趣的技术实践分享

前言

TG bot 里面存了不少优化消息,有时间可以处理一下

contexthelper 优化需求

V3 版本优化——增加范型

阅读下面这段代码:
好的,这段代码是用 Go 语言写的,它定义了一个用于在context.Context中存储和加载值的 API。这个 API 允许你将多个值与一个给定的键关联,并且能够检索到这些值。这是通过使用一个结构体valuesMap来实现的,该结构体有一个读写互斥锁来保证并发访问的安全性。代码中定义了四个函数:StoreStoreSingleValueLoadLoadAll
Store函数允许你存储一个或多个值与一个键关联。StoreSingleValue是一个特化版本,它只存储单个值。Load函数用于获取与键关联的第一个值。LoadAll函数返回与键关联的所有值的切片。
每个函数都接受一个context.Context和一个键名作为参数,StoreStoreSingleValue还接受要存储的值。这些函数通过检查上下文中是否存在valuesMap来决定是否需要创建一个新的valuesMap。如果需要,它会创建一个新的valuesMap并将其与一个特殊的键contextKey关联在上下文中。
这个 API 可以用在需要在上下文中传递额外状态的场景中,特别是在处理并发请求时,每个请求都可以有自己的状态。

这里能不能改成 value... T 呢? func Store[T any](ctx context.Context, key string, value T) context.Context {}

在 Go 语言中,value... T表示一个变参函数,允许你传递零个或多个T类型的参数。在你提供的Store函数签名中,使用value... T是合理的,因为这样可以让你存储一个或多个与键相关联的值。实际上,代码中的Store函数已经使用了value... T来实现这一功能。
如果你想要改变StoreSingleValue函数来接受一个或多个值而不是单个值,你可以将其参数列表中的value T替换为value... T。不过,这样做之后,StoreSingleValue函数就和Store函数的功能一样了,因为它们都能接受一个或多个值。如果你的目的是要让StoreSingleValue函数有与Store函数不同的行为,例如只接受单个值,那么就不应该做这样的修改。
总结一下,如果你想要StoreSingleValue函数接受多个值,可以这样修改:
但请注意,这样修改后,StoreSingleValue的行为将与Store函数相同,你可能需要重新考虑函数的命名和用途,以避免混淆。

store 支持多个值的话那么应该增加单元测试吗?

是的,当你修改了Store函数以支持接受多个值,或者对任何函数进行了修改时,增加或更新单元测试是非常重要的。单元测试可以帮助你验证函数是否按照预期工作,并且在未来的代码更改中保证函数的行为仍然正确。
针对Store函数接受多个值的情况,你应该编写测试来确保以下几点:
  1. 函数能够正确接受并存储单个值。
  1. 函数能够正确接受并存储多个值。
  1. 当使用相同的键存储多个值时,这些值都应该被存储,并且能够通过LoadAll函数检索到。
  1. 验证并发安全性,确保在并发环境下Store函数能够正确工作。
这里是一个简单的单元测试示例,用于测试Store函数:
单元测试是确保你的代码质量的关键部分,尤其是在公共 API 或库中,你应该为所有公开的函数和方法提供彻底的测试。这样可以减少未来修改代码时引入错误的风险,并增强代码的可靠性。

如果没有加上 value...,那么就不能 ctx = Store(ctx, key, val2, val3) 吗?

如果没有在Store函数的参数中使用value... T,那么你就不能使用Store(ctx, key, val2, val3)这样的调用方式来传递多个值。在 Go 语言中,value... T表示该参数可以接收任意数量的T类型的值,这被称为变参函数。
如果Store函数的定义是这样的:
go
那么它只能接收一个T类型的值作为参数。这意味着你只能传递一个值给value参数,如下所示:
如果你尝试传递多个值,比如:
这将会导致编译错误,因为Store函数不是变参函数,它不接受多于一个的value参数。
如果你需要存储多个值,你必须要使用value... T这样的变参定义,或者你需要调用Store函数多次,每次传递一个值,像这样:
但请注意,这样的调用方式会根据你Store函数内部的实现,可能会覆盖之前存储的值,除非你的实现是将新值追加到现有列表中。所以,如果你想要一次性存储多个值,使用value... T是更好的选择。

返回 0 值 (t T),这样修改是的代码更加简洁

在 Go 语言中,返回类型的零值是一种常见的做法,尤其是在出错或者找不到值的情况下。零值是指一个变量在没有显式初始化时的默认值。例如,数值类型的零值是0,布尔类型的零值是false,指针类型的零值是nil,而对于切片、映射、通道、接口、函数等类型,零值也是nil
在你提供的Load函数中,如果在valuesMap中找不到对应的键,或者类型断言失败,函数会返回类型T的零值。这确实是一种简洁且有效的处理方式,因为它避免了在函数中多次重复编写创建零值变量的代码。
以下是Load函数的一个简化示例,其中返回类型T的零值:
在这个函数中,var zero T声明了一个类型为T的变量zero,其值是类型T的零值。如果上下文中没有找到值或类型断言失败,函数就会返回这个零值。
这种方式是 Go 语言常用的惯例,它使得代码简洁且易于理解,同时也避免了返回nil或者抛出异常,因为在 Go 中,通常是通过返回零值和错误值来处理异常情况。
大厂程序员都在用什么工具绘图?Handraw: 支持中文手写效果的 Excalidraw - 少数派免费的 MongoDB 云数据库 (MongoDB Atlas)使用教程
Loading...