Created time
Apr 3, 2024 06:52 AM
date
status
category
Origin
summary
tags
type
URL
icon
password
slug
本文由 简悦 SimpRead 转码, 原文地址 vlog.jiejaitt.top
有趣的技术实践分享
前言
TG bot 里面存了不少优化消息,有时间可以处理一下
contexthelper 优化需求
V3 版本优化——增加范型
阅读下面这段代码:
好的,这段代码是用 Go 语言写的,它定义了一个用于在
context.Context
中存储和加载值的 API。这个 API 允许你将多个值与一个给定的键关联,并且能够检索到这些值。这是通过使用一个结构体valuesMap
来实现的,该结构体有一个读写互斥锁来保证并发访问的安全性。代码中定义了四个函数:Store
、StoreSingleValue
、Load
和LoadAll
。Store
函数允许你存储一个或多个值与一个键关联。StoreSingleValue
是一个特化版本,它只存储单个值。Load
函数用于获取与键关联的第一个值。LoadAll
函数返回与键关联的所有值的切片。每个函数都接受一个
context.Context
和一个键名作为参数,Store
和StoreSingleValue
还接受要存储的值。这些函数通过检查上下文中是否存在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
函数接受多个值的情况,你应该编写测试来确保以下几点:- 函数能够正确接受并存储单个值。
- 函数能够正确接受并存储多个值。
- 当使用相同的键存储多个值时,这些值都应该被存储,并且能够通过
LoadAll
函数检索到。
- 验证并发安全性,确保在并发环境下
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 中,通常是通过返回零值和错误值来处理异常情况。