Merge branch 'main' of https://github.com/OSHMKUFA5100/lab
This commit is contained in:
commit
e6fe90a7c0
6
.gitignore
vendored
6
.gitignore
vendored
@ -27,4 +27,8 @@ build/
|
||||
|
||||
# ---- 操作系统 ----
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# ---- Note 目录 ----
|
||||
note/assets/
|
||||
note/项目/
|
||||
48
go/testing/normal_test.go
Normal file
48
go/testing/normal_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNormal(t *testing.T) {
|
||||
numbers := map[int][]int{
|
||||
1: {8, 2, 4, 4},
|
||||
2: {0, 5, 3},
|
||||
3: {1},
|
||||
}
|
||||
for _, numbers := range numbers {
|
||||
middle := GetMiddNumber(numbers)
|
||||
t.Log(middle)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetMiddNumber(numbers []int) float64 {
|
||||
sort.Ints(numbers)
|
||||
length := len(numbers)
|
||||
isOddNUmber := length%2 == 1
|
||||
if !isOddNUmber {
|
||||
return float64(numbers[length/2-1]+numbers[length/2]) / 2.0
|
||||
}
|
||||
return float64(numbers[length/2])
|
||||
}
|
||||
|
||||
func TestChannel(t *testing.T) {
|
||||
var ball = make(chan string)
|
||||
kickBall := func(playerName string) {
|
||||
for {
|
||||
t.Log(<-ball, "传球", "\n")
|
||||
time.Sleep(time.Second)
|
||||
ball <- playerName
|
||||
}
|
||||
}
|
||||
go kickBall("张三")
|
||||
go kickBall("李四")
|
||||
go kickBall("王二麻子")
|
||||
go kickBall("刘大")
|
||||
ball <- "裁判" // 开球
|
||||
var c chan bool // 一个零值nil通道
|
||||
<-c // 永久阻塞在此
|
||||
}
|
||||
303
note/归档/zero-examples.md
Normal file
303
note/归档/zero-examples.md
Normal file
@ -0,0 +1,303 @@
|
||||
# HTTP
|
||||
|
||||
## 上传文件
|
||||
|
||||
> **https://github.com/zeromicro/zero-examples/tree/main/http/upload**
|
||||
|
||||
### 前端
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<form
|
||||
enctype="multipart/form-data"
|
||||
action="http://localhost:8888/upload"
|
||||
method="post"
|
||||
>
|
||||
<input type="file" name="myFile" />
|
||||
<input type="submit" value="upload" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
> **参数说明**
|
||||
|
||||
- `enctype="multipart/form-data"` 用于支持文件的二进制传输
|
||||
|
||||
- `<input type="file">` 让用户挑选本地文件
|
||||
|
||||
- `action` 和 `method`,将数据以 `POST` 方式提交到后端地址
|
||||
|
||||
|
||||
|
||||
### 后端
|
||||
|
||||
```yaml
|
||||
Name: upload-api
|
||||
Host: 0.0.0.0
|
||||
Port: 8888
|
||||
MaxBytes: 1073741824
|
||||
Timeout: 30000
|
||||
```
|
||||
|
||||
> **yaml文件需要设置上传的最大字节,并且如果为大文件,需要考虑超时时间设置是否合理**
|
||||
|
||||
```go
|
||||
func (l *UploadLogic) Upload(r *http.Request) (resp *types.Response, err error) {
|
||||
err = r.ParseMultipartForm(10 << 27)
|
||||
if err != nil {
|
||||
fmt.Println("错误发生:", err)
|
||||
return nil, err
|
||||
}
|
||||
file, handler, err := r.FormFile("myFile")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fmt.Printf("Uploaded File: %+v\n", handler.Filename)
|
||||
fmt.Printf("File Size: %+v\n", handler.Size)
|
||||
fmt.Printf("MIME Header: %+v\n", handler.Header)
|
||||
|
||||
tempFile, err := os.Create(path.Join(".", handler.Filename))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
defer tempFile.Close()
|
||||
io.Copy(tempFile, file)
|
||||
|
||||
return &types.Response{
|
||||
OK: 0,
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
> **API逻辑说明**
|
||||
|
||||
- 需要在handler里面将`*http.Request`传递到逻辑层
|
||||
|
||||
- `ParseMultipartForm`用于解析 `multipart/form-data` 类型的请求体
|
||||
|
||||
主要作用是:
|
||||
|
||||
解析表单字段(包括文件上传字段)
|
||||
|
||||
将请求体拆分成多个部分(parts),并填充到 `r.MultipartForm` 中
|
||||
|
||||
内存与磁盘分配:最多在内存中保留 `maxFileSize` 字节,超出的部分会写入临时文件
|
||||
|
||||
- `FormFile(key string)` 从已解析的 `r.MultipartForm` 中提取名为 `"myFile"` 的文件部分
|
||||
|
||||
- `tempFile, err := os.Create(path.Join(".", handler.Filename))`将文件上传到当前目录
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# DTM
|
||||
|
||||
## 基础概念
|
||||
|
||||
- **AP(Application)**:应用程序,发起全局事务请求。
|
||||
- **TM(Transaction Manager)**:事务协调者,负责协调分布式事务的执行流程。
|
||||
- **RM(Resource Manager)**:资源管理者,例如订单服务、库存服务等,执行具体业务与补偿逻辑
|
||||
- **事务分支**:我们把每个服务管理的全局事务组成部分,称为事务分支,例如前面的转账,分为转出和转入两个事务分支
|
||||
- **分支操作**:每个事务分支,在SAGA、XA、TCC等事务模式下,会有多个操作,例如转出事务分支,包括正向操作TransOut和TransOutCompensate
|
||||
- **本地事务**:转出事务分支中的正向操作,通常会开启一个事务,对余额进行扣减,我们将数据操作的这个事务,称为本地事务
|
||||
- **GID**:全局事务ID,用于标记全局事务,必须唯一。该ID可以采用UUID生成,也可以使用业务上的ID,例如订单ID等
|
||||
|
||||
| 模式 | 场景 | 典型使用 |
|
||||
| ---------- | ---------------------------------------- | --------------------------------- |
|
||||
| 二阶段消息 | 需要确保消息通知或缓存更新与本地事务同步 | 发短信/推送、消息投递、缓存一致性 |
|
||||
| Saga | 流程复杂、长链路、不需强一致性 | 电商下单→扣库存→支付等微服务流程 |
|
||||
| TCC | 强一致、高隔离资源场景 | 金融系统、库存冻结、大额支付 |
|
||||
|
||||
## 二阶段消息
|
||||
|
||||
是dtm首创的事务模式,用于替换本地事务表和事务消息这两种现有的方案。它能够保证本地事务的提交和全局事务提交是“原子的”,适合解决不需要回滚的分布式事务场景,比如发消息、更新缓存等
|
||||
|
||||
- **准备阶段**(Prepare) ,应用先发一个准备信号给 DTM Server,表示“我现在要做本地事务了”。DTM Server 接收到后先记录这个请求,但不触发后续通知。
|
||||
- 执行本地事务, 应用开始执行本地事务(如写数据库、扣款),并在同一个数据库里,记录这次全局事务的 gid(全局事务 ID)。这保证了后续可以根据 gid 判断本地事务是否已成功。
|
||||
- **提交阶段**(Submit), 本地事务成功后,应用再向 DTM 提交提交请求。DTM 执行这个操作后,才真正触发下游服务或消息投递。开始调用其他微服务或消息队列,实现完整的全局动作。
|
||||
|
||||
**优点:**
|
||||
|
||||
- 保证“本地事务 + 消息”业务要么同时成功,否则都不执行。(强触发保障)
|
||||
- 对开发者透明,业务侵入小。
|
||||
|
||||
**缺点:**
|
||||
|
||||
- 需要开发一套 Prepare/Submit 调用,系统需定期监控、回查状态。
|
||||
- 不适用于需要复杂补偿的场景。
|
||||
|
||||
## SAGA
|
||||
|
||||
核心思想是将长事务拆分为多个短事务,由Saga事务协调器协调,如果每个短事务都成功提交完成,那么全局事务就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作。例如我们要进行一个类似于银行跨行转账的业务,将A中的30元转给B,根据Saga事务的原理,我们将整个全局事务,切分为以下服务:
|
||||
|
||||
- **转出**(TransOut)服务,这里转出将会进行操作A-30
|
||||
- **转出补偿**(TransOutCompensate)服务,回滚上面的转出操作,即A+30
|
||||
- **转入**(TransIn)服务,转入将会进行B+30
|
||||
- **转入补偿**(TransInCompensate)服务,回滚上面的转入操作,即B-30
|
||||
|
||||
**优点:**
|
||||
|
||||
- 流程自然、开发简单,只要为操作实现补偿逻辑即可。
|
||||
- 对资源无锁设计,支持高并发、长流程,性能佳。
|
||||
|
||||
**缺点:**
|
||||
|
||||
- 是最终一致性,存在临时中间状态(如库存已扣但未支付)。
|
||||
- 无事务隔离,可能出现脏写或并发冲突。
|
||||
- 补偿逻辑可能复杂易错(幂等、防重复)。
|
||||
|
||||
## TCC
|
||||
|
||||
TCC 是一种“预留-确认-取消”的事务模式,将事务分为三个阶段,高精度控制点 的场景,比如:支付系统、资金冻结、库存预扣等
|
||||
|
||||
- **Try** 阶段:尝试执行,完成所有业务检查(一致性), 预留必须业务资源(准隔离性)
|
||||
- **Confirm** 阶段:如果所有分支的Try都成功了,则走到Confirm阶段。Confirm真正执行业务,不作任何业务检查,只使用 Try 阶段预留的业务资源
|
||||
- **Cancel** 阶段:如果所有分支的Try有一个失败了,则走到Cancel阶段。Cancel释放 Try 阶段预留的业务资源。
|
||||
|
||||
**优点:**
|
||||
|
||||
- 强一致性:通过 Try 预留资源,Confirm/Cancel 明确执行或回滚,避免中间状态。
|
||||
- 高并发友好,资源锁粒度小;性能优于传统 XA/2PC。
|
||||
|
||||
**缺点:**
|
||||
|
||||
- 业务侵入性高,每个参与方需实现三个操作(Try/Confirm/Cancel)。
|
||||
- 实现复杂:需处理悬挂、空回滚、幂等、补偿重试等问题。
|
||||
|
||||
## SAGA实践
|
||||
|
||||
- 准备RM和DTM数据表
|
||||
|
||||
[GitHub地址](https://github.com/dtm-labs/dtm/tree/main/sqls)
|
||||
|
||||
- DTM配置
|
||||
|
||||
[GitHub地址](https://github.com/dtm-labs/dtm/blob/main/conf.sample.yml)
|
||||
|
||||
- docker部署参考配置
|
||||
|
||||
```yaml
|
||||
LogLevel: 'info'
|
||||
Server:
|
||||
HttpPort: 36789 #HTTP port
|
||||
GrpcPort: 36790 #Grpc port
|
||||
Store:
|
||||
Driver: "mysql" # 数据库类型
|
||||
Host: "mysql" # 使用容器名
|
||||
Port: 3306
|
||||
User: "root"
|
||||
Password: "root"
|
||||
Db: "dtm"
|
||||
MicroService:
|
||||
Driver: "dtm-driver-gozero" #使用go-zero的注册服务发现驱动
|
||||
Target: "etcd://etcd:2379/dtmservice" # 使用容器名,当前dtm的server直接注册到微服务所在的etcd集群中使用
|
||||
EndPoint: "dtm:36790" # 使用容器名,集群中的微服务可以直接通过etcd获得此地址跟dtm交互
|
||||
```
|
||||
|
||||
- go-zero的yaml参考配置
|
||||
|
||||
```yaml
|
||||
#AP使用etcd的配置
|
||||
Etcd:
|
||||
Hosts:
|
||||
- etcd:2379
|
||||
Key: order.api
|
||||
#RM使用etcd的配置
|
||||
OrderRpc:
|
||||
Etcd:
|
||||
Hosts:
|
||||
- etcd:2379
|
||||
Key: order.rpc
|
||||
#RM使用etcd的配置
|
||||
StockRpc:
|
||||
Etcd:
|
||||
Hosts:
|
||||
- etcd:2379
|
||||
Key: stock.rpc
|
||||
```
|
||||
|
||||
SAGA 事务编排使用步骤
|
||||
|
||||
```go
|
||||
// dtm服务在etcd中的调用地址
|
||||
var dtmServer = "etcd://localhost:2379/dtmservice"
|
||||
|
||||
// 从配置中通过BuildTarget获得对应RM的etcd调用地址
|
||||
orderTarget, err := l.svcCtx.Config.OrderRpcConf.BuildTarget()
|
||||
stockTarget, err := l.svcCtx.Config.StockRpcConf.BuildTarget()
|
||||
|
||||
// 构造对应的请求结构体,用于后面的本地事务的执行或者回滚补偿
|
||||
createOrderReq := &order.CreateReq{UserId: req.UserId, GoodsId: req.GoodsId, Num: req.Num}
|
||||
deductReq := &stock.DecuctReq{GoodsId: req.GoodsId, Num: req.Num}
|
||||
|
||||
// 使用dtmgrpc注册一个全局事务ID,用于标记全局事务
|
||||
gid := dtmgrpc.MustGenGid(dtmServer)
|
||||
|
||||
// 开启全局事务,并提交
|
||||
// dtm需要从dtm服务器调用该方法,所以不走强类型,而是走动态的url: busiServer+"/trans.TransSvc/TransOut"
|
||||
// "/trans.TransSvc/TransOut"对应的是grpc_pb.go文件中Invoke方法所使用的路径
|
||||
saga := dtmgrpc.NewSagaGrpc(dtmServer, gid).
|
||||
Add(
|
||||
orderTarget+"/pb.order/create",
|
||||
orderTarget+"/pb.order/createRollback",
|
||||
createOrderReq,
|
||||
).
|
||||
Add(
|
||||
stockTarget+"/pb.stock/deduct",
|
||||
stockTarget+"/pb.stock/deductRollback",
|
||||
deductReq,
|
||||
)
|
||||
err = saga.Submit()
|
||||
```
|
||||
|
||||
服务实现(包含子事务屏障)
|
||||
|
||||
```go
|
||||
// 从 gRPC 请求上下文中提取分布式事务信息,构建一个用于管理子事务屏障的对象
|
||||
barrier, err := dtmgrpc.BarrierFromGrpc(l.ctx)
|
||||
// 获取一个sqlx的数据库连接
|
||||
db, err := sqlx.NewMysql(l.svcCtx.Config.DB.DataSource).RawDB()
|
||||
|
||||
if err != nil {
|
||||
// 一般数据库不会错误不需要dtm回滚,就让他一直重试
|
||||
// 返回为status.Error(codes.Internal, err.Error()),会让dtm一直重试,不会回滚,直到
|
||||
// 返回为status.Error(codes.Aborted, dtmcli.ResultFailure),会让dtm立刻调用回滚方法
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
// 开启本地事务(这里没写,正常应该在本地事务中再开启子事务屏障进行业务处理
|
||||
// 将业务逻辑包裹在子事务屏障的保护下执行
|
||||
if err := barrier.CallWithDB(db, func(tx *sql.Tx) error {
|
||||
order := new(model.Order)
|
||||
order.GoodsId = in.GoodsId
|
||||
order.Num = in.Num
|
||||
order.UserId = in.UserId
|
||||
|
||||
_, err = l.svcCtx.OrderModel.Insert(tx, order)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建订单失败 err : %v , order:%+v \n", err, order)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
// 同上,让dtm一直重试,不回滚
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
// 补偿操作跟上面差不多,就是业务逻辑修改
|
||||
```
|
||||
|
||||
70
note/资源/AI/OMO配置.md
Normal file
70
note/资源/AI/OMO配置.md
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
|
||||
## oh-my-openagent
|
||||
|
||||
### Agent角色
|
||||
|
||||
| **Agent 名称** | **属性** | **一句话特点** |
|
||||
| ----------------- | -------- | ------------------------------------------------------------ |
|
||||
| Sisyphus | 台前主控 | 项目总管、日常聊天与轻量开发入口,居中调度,维持记忆的多面手 |
|
||||
| Prometheus | 台前主控 | 复杂需求的规划者、Gap(差距)分析师,只出谋划策(写 Plan),不动手写代码 |
|
||||
| Atlas | 台前主控 | 流水线执行者、项目经理,盯着 TODO 督战的施工队包工头 |
|
||||
| Hephaestus | 台前主控 | 火神、地狱级 Bug 终结者,单兵作战,不计成本死磕疑难杂症 |
|
||||
| Oracle | 幕后工具 | 代码审查员、安全顾问,挑刺、CR、架构安全性把关 |
|
||||
| Momus | 幕后工具 | Debug 专家,专门吃报错日志并给出修复建议 |
|
||||
| Metis | 幕后工具 | 质检员、对齐审计,检查代码跟计划对不对齐,防止跑偏 |
|
||||
| Sisyphus-junior | 幕后工具 | 基层打工人、代码搬砖牛马,真正动手改文件的“牛马码农” |
|
||||
| Explore | 幕后工具 | 代码库检索员,在代码库里疯狂乱窜、扫图、找文件 |
|
||||
| Librarian | 幕后工具 | 文档与知识检索员,专门翻文档、查第三方库用法 |
|
||||
| Multimodal-looker | 幕后工具 | 视觉质检员,负责看截图、核对 UI 视觉问题 |
|
||||
|
||||
### 内置分类预设
|
||||
|
||||
| 分类名称(Category) | 预设心智与应用场景 |
|
||||
| ------------------ | ------------------------------------------------------------ |
|
||||
| visual-engineering | **像素级前端 UI 专家**。专门处理前端组件、页面样式美化、CSS 动画调整,默认偏向调度带有视觉能力的模型。 |
|
||||
| deep | **目标导向的硬核攻坚战**。针对棘手难啃的底层问题,严格遵循“单次调用:一个目标 + 一个交付物”原则,死磕到底。 |
|
||||
| quick | **低成本牛马杂活线**。处理单文件小改动、错别字修复、简单注释补充。默认绑定极便宜的 Mini 或 Flash 模型来帮你疯狂省钱。 |
|
||||
| ultrabrain | 高浓度脑力推演 |
|
||||
| writing | **散文与技术文档写手**。专门用来编写官方 Markdown 文档、技术方案白皮书或代码内说明。 |
|
||||
|
||||
|
||||
|
||||
## oh-my-opencode-slim
|
||||
|
||||
### 预设
|
||||
|
||||
`oh-my-opencode-slim.json`中的顶级字段`presets`为预设对象数组,默认设置了两套:一套是`openai`,一套是`opencode-go`。可以自行增删预设或者修改`agent`角色的模型。
|
||||
|
||||
```
|
||||
# 在opencode会话中输入
|
||||
/preset <name>
|
||||
```
|
||||
|
||||
### Agent角色
|
||||
|
||||
| **Agent 名称** | **角色** | **模型选择** |
|
||||
| -------------- | ----------------------- | ------------------------------------------------------------ |
|
||||
| Orchestrator | 首席委派者和战略协调员 | 选择您的默认、最强的全能型编程模型。Orchestrator 既是核心编程智能体,又是委派者,因此它需要强大的实现能力、出色的判断力和可靠的指令遵循度。 |
|
||||
| Explorer | 代码库侦察 | 选择快速、低成本的模型。Explorer 处理宽泛的侦察工作,因此速度 and 效率通常比使用最强推理模型更重要。 |
|
||||
| Oracle | 战略顾问和终极调试者 | 选择您最强的高推理模型,用于架构设计、疑难调试、方案权衡以及代码审查。 |
|
||||
| Council | 多LLM共识与提炼 | 使用一个强大的综合提炼模型作为 Council 智能体本身,并选择多样化的模型作为议员。Council 的价值在于对比不同的模型视角,而不仅仅是在所有地方都选择同一个最强的模型。 |
|
||||
| Librarian | 外部知识检索 | 选择快速、低成本的模型。Librarian 处理调研和文档查询,因此速度和效率通常比使用最强推理模型更重要。 |
|
||||
| Designer | UI/UX实现和极致视觉呈现 | 选择在 UI/UX 判断、前端实现和视觉打磨方面表现强劲的模型。 |
|
||||
| Fixer | 快速实现专家 | 选择一个快速、可靠的编程模型来执行常规且范围明确的开发工作。Fixer 通常从 Orchestrator 接收具体的计划或受限的指令,非常适合高效执行诸如编写测试、更新测试和直接的代码更改等任务。 |
|
||||
| Observer | 多模态处理 | 如果Orchestrator模型不是多模态模型,可以启用 Observer 来处理图像、屏幕截图、PDF 以及其他视觉文件。 |
|
||||
|
||||
### Skill分配
|
||||
|
||||
## 技能分配
|
||||
|
||||
控制每个代理人可以使用的技能`~/.config/opencode/oh-my-opencode-slim.json`(或`.jsonc`):
|
||||
|
||||
| 句法 | 意义 |
|
||||
| ------------------- | ------------------------------- |
|
||||
| `["*"]` | 所有已安装的技能 |
|
||||
| `["*", "!codemap"]` | 除以下技能外的所有技能`codemap` |
|
||||
| `["simplify"]` | 仅有的`simplify` |
|
||||
| `[]` | 没有技能 |
|
||||
| `["!*"]` | 拒绝所有技能 |
|
||||
|
||||
70
note/资源/DevOps/Git/常用命令.md
Normal file
70
note/资源/DevOps/Git/常用命令.md
Normal file
@ -0,0 +1,70 @@
|
||||
### 常用命令
|
||||
|
||||
#### 一、分支管理
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| -------------------- | -------------------------------------- | ---------------------------- |
|
||||
| 查看本地分支 | `git branch` | 显示所有本地分支 |
|
||||
| 查看远程分支 | `git branch -r` | 显示远程分支 |
|
||||
| 创建新分支 | `git checkout -b feature/xxx` | 基于当前分支创建并切换新分支 |
|
||||
| 基于远程创建本地分支 | `git checkout -b dev origin/dev` | 跟踪远程分支创建 |
|
||||
| 删除本地分支 | `git branch -d feature/xxx` | 删除(已合并)本地分支 |
|
||||
| 删除远程分支 | `git push origin --delete feature/xxx` | 删除远程分支 |
|
||||
| 重命名分支 | `git branch -m old new` | 修改分支名 |
|
||||
|
||||
#### 二、提交相关
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| ------------------ | ------------------------------- | ------------------------------------------ |
|
||||
| 添加到暂存区 | `git add .` 或 `git add <file>` | 添加改动文件 |
|
||||
| 提交代码 | `git commit` | 使用文本编辑器编写提交信息后提交 |
|
||||
| 提交代码 | `git commit -m "描述信息"` | 提交到本地仓库,可使用多个`-m`提交多行信息 |
|
||||
| 修改上一次提交信息 | `git commit --amend` | 用于补充或改描述 |
|
||||
| 查看提交历史 | `git log --oneline` | 简洁模式显示历史 |
|
||||
|
||||
#### 三、远程操作
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| ---------------- | --------------------------------------------------------- | ------------------- |
|
||||
| 克隆仓库 | `git clone <url>` | 拉取远程项目 |
|
||||
| 拉取远程代码 | `git pull` | 获取并合并远程分支 |
|
||||
| 推送代码 | `git push` | 推送当前分支到远程 |
|
||||
| 推送并设置上游 | `git push -u origin <branch>` | 建立跟踪关系 |
|
||||
| 查看远程地址 | `git remote -v` | 显示远程仓库地址 |
|
||||
| 远程查询所有标签 | git ls-remote --tags https://github.com/xxx.git \| grep X | 查看X相关的所有标签 |
|
||||
|
||||
#### 四、合并与变基
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| -------------- | ------------------------------------ | ------------------------------- |
|
||||
| 合并分支 | `git merge feature/xxx` | 把目标分支合并进当前分支 |
|
||||
| 取消合并 | `git merge --abort` | 终止合并,直接回退到合并前的状态 |
|
||||
| 变基(rebase) | `git rebase dev` | 让你的提交在最新 `dev` 上 |
|
||||
| 解决冲突后继续 | `git add . && git rebase --continue` | 继续变基或合并流程 |
|
||||
|
||||
#### 五、查看状态和差异
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| ---------------- | ------------------- | ---------------------------- |
|
||||
| 查看状态 | `git status` | 当前分支、暂存区、工作区状态 |
|
||||
| 查看修改内容 | `git diff` | 查看未暂存的更改 |
|
||||
| 查看暂存内容差异 | `git diff --cached` | 查看已 add 的更改 |
|
||||
|
||||
#### 六、撤销操作
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| ----------------------- | ------------------------- | -------------------- |
|
||||
| 撤销 add | `git reset <file>` | 把文件移出暂存区 |
|
||||
| 撤销 commit(保留修改) | `git reset --soft HEAD~1` | 撤销最近一次提交 |
|
||||
| 丢弃修改 | `git checkout -- <file>` | 丢弃对文件的本地更改 |
|
||||
| 丢弃所有工作区修改 | `git reset --hard` | 恢复到最后一次提交 |
|
||||
|
||||
#### 七、其他常用
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
| ---------------------- | ------------------------------------------------------------ | ---- |
|
||||
| 查看当前分支 | `git branch --show-current` 或 `git rev-parse --abbrev-ref HEAD` | |
|
||||
| 查看某次提交内容 | `git show <commit-id>` | |
|
||||
| 切换到上一个分支 | `git checkout -` | |
|
||||
| 清理无效引用 | `git remote prune origin` | |
|
||||
| 从远程仓库获取所有标签 | `git fetch origin --tags` | |
|
||||
117
note/资源/DevOps/Git/提交规范.md
Normal file
117
note/资源/DevOps/Git/提交规范.md
Normal file
@ -0,0 +1,117 @@
|
||||
|
||||
|
||||
[来源网站](https://www.conventionalcommits.org/zh-hant/v1.0.0/)
|
||||
|
||||
## 提交说明
|
||||
|
||||
### 基础结构
|
||||
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
|
||||
# 译文
|
||||
|
||||
<类型>[可选 范围]: <描述>
|
||||
|
||||
[可选 正文]
|
||||
|
||||
[可选 脚注]
|
||||
```
|
||||
|
||||
### 类型(type)
|
||||
|
||||
- feat: 表示在代码库中新增了一个功能;
|
||||
- fix: 表示在代码库中修复了一个 bug;
|
||||
|
||||
- build: 用于修改项目构建系统或外部依赖,例如升级依赖版本等;
|
||||
- chore: 用于其他不修改`src`或`test`文件的杂项任务,例如更新`.gitignore`、修改编辑器配置等;
|
||||
- ci: 用于修改持续集成/持续部署的配置与脚本,例如`GitHub Actions`、`Jenkins`、`Travis` 等工作流;
|
||||
- docs: 用于修改文档,例如修改`README`文件、API文档等;
|
||||
- style: 用于修改代码格式(不影响代码逻辑),例如调整缩进、空格、分号、引号风格等;
|
||||
- refactor: 用于重构代码,例如修改代码结构、变量名、函数名等但不修改功能逻辑;
|
||||
- improvement: 用于对现有实现进行改进,例如优化算法、增强健壮性等(不涉及新功能或 bug 修复);
|
||||
- revert: 用于回退之前的提交,描述应使用被回退提交的标题,并在脚注中用 `Refs:` 引用被回退的 commit SHA;
|
||||
- perf: 用于优化性能,例如提升代码的性能、减少内存占用等;
|
||||
- wip: 用于保存尚未完成的工作进度(Work In Progress);
|
||||
- test: 用于修改测试用例,例如添加、删除、修改代码的测试用例等;
|
||||
|
||||
> 破坏性变更**必须**在提交信息中标记出来,有两种方式:
|
||||
>
|
||||
> 1.在 `<类型>[可选 范围]` 后、冒号前添加 `!`,例如:`feat!: ...` 或 `refactor(api)!: ...`
|
||||
>
|
||||
> 2.*在脚注中添加* `BREAKING CHANGE: <描述>`
|
||||
>
|
||||
> 这两种方式可以同时使用,也可以只用其一。
|
||||
|
||||
### 范围(Scope)
|
||||
|
||||
范围用于标识本次修改影响的模块或组件,例如:
|
||||
|
||||
- feat(auth): ... (auth 模块)
|
||||
|
||||
- fix(parser): ... (parser 模块)
|
||||
|
||||
- build(deps): ... (依赖管理)
|
||||
|
||||
范围名称建议使用小写英文,多个单词用 `-` 连接,例如 `user-profile`。
|
||||
|
||||
### 描述(description)
|
||||
|
||||
描述用于简要概括本次变更的内容,要求:
|
||||
|
||||
- 使用祈使语气、现在时态(例如用 "add" 而非 "added" 或 "adds");
|
||||
|
||||
- 小写开头,末尾不加句号;
|
||||
|
||||
- 长度建议控制在50个字符以内(中文约 25 个字);
|
||||
|
||||
### 正文(Body)
|
||||
|
||||
正文是可选的,用于对本次变更进行更详细的说明,包括:
|
||||
|
||||
- 变更的动机(为什么这样做)
|
||||
|
||||
- 与之前行为的对比
|
||||
|
||||
- 实现方案的简要说明
|
||||
|
||||
正文与描述之间**必须**空一行,正文内部段落之间也可以空行分隔。
|
||||
|
||||
### 脚注(Footer)
|
||||
|
||||
脚注用于记录元信息,常见用法:
|
||||
|
||||
- `BREAKING CHANGE: <描述>` — 标记破坏性变更;
|
||||
|
||||
- `Closes #123` 或 `Fixes #456` — 关联 Issue/PR;
|
||||
|
||||
- `Refs: abc123` — 引用相关提交;
|
||||
|
||||
- `Reviewed-by: <name>` — 标记审查者;
|
||||
|
||||
- `Co-authored-by: <name> <email>` — 标记共同作者;
|
||||
|
||||
## 示例
|
||||
|
||||
### 基础功能提交
|
||||
feat(auth): add JWT token refresh mechanism
|
||||
|
||||
### Bug 修复(含关联 issue)
|
||||
fix(parser): handle empty string input edge case
|
||||
|
||||
Closes #123
|
||||
|
||||
### 破坏性变更(使用 ! 前缀)
|
||||
feat(api)!: change user endpoint response format
|
||||
|
||||
BREAKING CHANGE: the `GET /api/users` endpoint now returns
|
||||
a paginated response instead of a flat array.
|
||||
|
||||
### 回退提交
|
||||
revert: remove experimental cache layer
|
||||
|
||||
Refs: a1b2c3d
|
||||
24
note/资源/DevOps/Linux/常用命令.md
Normal file
24
note/资源/DevOps/Linux/常用命令.md
Normal file
@ -0,0 +1,24 @@
|
||||
### SSH
|
||||
|
||||
#### 快速连接服务器
|
||||
|
||||
在ssh的配置文件`~/.ssh/config`中可以设置常用的服务配置,这样就可以直接使用`ssh myserver`快速连接服务器了
|
||||
|
||||
```
|
||||
Host myserver
|
||||
HostName your-server.com
|
||||
Port 2222
|
||||
User ubuntu
|
||||
IdentityFile ~/.ssh/mykey
|
||||
```
|
||||
|
||||
#### 本地转发
|
||||
|
||||
```bash
|
||||
# 使用示例
|
||||
ssh -L 25432:localhost:5432 ubuntu@your-server.com
|
||||
```
|
||||
|
||||
**作用**:以本地端口25432请求远程服务器,在远程服务器看来,这是以远程`localhost:5432`发起的请求
|
||||
|
||||
**使用场景**:当远程服务器某服务限制了只接收远程服务器的127.0.0.1连接,这时候又需要远程连接这个服务,这样的话就能和访问本地服务一样访问了
|
||||
84
note/资源/DevOps/Linux/操作系统.md
Normal file
84
note/资源/DevOps/Linux/操作系统.md
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
|
||||
## 程序、进程与线程
|
||||
|
||||
### 程序
|
||||
|
||||
#### 定义
|
||||
|
||||
程序是存储在硬盘的一组指令集和,它是对计算任务的完整描述,是一个被动实体。类似于一本菜谱,记录了完整的烹饪步骤。
|
||||
|
||||
#### 核心特征
|
||||
|
||||
| 属性 | 说明 |
|
||||
| :------------- | :-------------------------------------------------------- |
|
||||
| **静态性** | 程序是一个文件(如 .exe、.go),不占用 CPU 或内存执行资源 |
|
||||
| **持久性** | 可长期存在于存储介质上 |
|
||||
| **无生命周期** | 没有创建、运行、消亡的状态变迁 |
|
||||
|
||||
### 进程
|
||||
|
||||
#### 定义
|
||||
|
||||
进程是程序的一次动态执行过程,是操作系统进行资源分配的基本单位。它就像按照菜谱进行烹饪的过程,需要占用资源,有始有终。它由以下三部分构成。
|
||||
|
||||
| 组成部分 | 作用 |
|
||||
| :-------------------- | :----------------------------------------------------- |
|
||||
| **程序段** | 描述进程要完成的功能,是控制进程执行的指令集 |
|
||||
| **数据段** | 程序执行时所需的数据和工作区(全局变量、堆等) |
|
||||
| **进程控制块(PCB)** | 包含进程的描述信息和控制信息,是**进程存在的唯一标志** |
|
||||
|
||||
#### 核心特征
|
||||
|
||||
- **动态性**:进程有生命周期(创建 → 就绪 → 运行 → 阻塞 → 终止)
|
||||
- **独立性**:每个进程拥有独立的地址空间(虚拟内存空间、代码、数据、系统资源的集合)
|
||||
- **并发性**:多个进程可在宏观上同时运行
|
||||
- **资源拥有者**:进程拥有独立的文件描述符、环境变量、用户ID等资源
|
||||
|
||||
### 线程
|
||||
|
||||
#### 定义
|
||||
|
||||
线程是CPU进行运算调度的最小单位,是进程中的一条执行路径,一个进程至少有一个线程(也就是主线程)。它就像多位厨师共用厨房的资源(水、灶台、食材等),但是每人也都有自己的独有的刀具、围裙等,他们需要协调使用厨房做菜。
|
||||
|
||||
#### 核心特征
|
||||
|
||||
线程虽然共享进程的资源,但每个线程拥有自己的**私有数据**:
|
||||
|
||||
| **独有内容** | **说明** |
|
||||
| :------------------ | :--------------------------------- |
|
||||
| 线程 ID | 唯一标识 |
|
||||
| 寄存器状态 | 包括程序计数器(PC)和栈指针 |
|
||||
| 栈 | 独立运行栈,用于函数调用和局部变量 |
|
||||
| 信号掩码 | 线程级别的信号处理设置 |
|
||||
| 优先级 | 调度优先级 |
|
||||
| 线程专用存储(TLS) | 线程私有的全局变量 |
|
||||
|
||||
|
||||
|
||||
## 用户态与内核态
|
||||
|
||||
### 内核态
|
||||
|
||||
运行操作系统内核代码,拥有对硬件的完全控制权,负责管理内存、进程、文件系统、网络等底层资源。
|
||||
|
||||
### 用户态
|
||||
|
||||
运行用户应用程序,无法直接访问硬件或内核数据结构,必须通过 系统调用(System Call)请求内核代为执行特权操作。
|
||||
|
||||
### 切换过程
|
||||
|
||||
为了保护系统安全与稳定,操作系统会对CPU的执行权限进行分级,不同的CPU架构有不同的等级,但是通常都遵循应用在最低特权级(用户态)运行,内核在次高特权级(内核态)运行,通过CPU硬件强制隔离特权操作。当在X86架构的CPU运行时,一个应用程序需要执行特权操作(比如读写文件),过程大致是这样的:
|
||||
|
||||
1. **触发**
|
||||
程序调用 `read()` 等库函数,最终执行 CPU 的 `syscall` 指令。这条指令告诉 CPU:“我要切换到内核态干正事”。
|
||||
2. **CPU 硬件自动切换**
|
||||
CPU 在硬件层面做三件关键事:
|
||||
- 把特权级从 **Ring 3(用户态)** 切换为 **Ring 0(内核态)**。
|
||||
- 将栈指针从用户栈切换到**内核栈**(从 MSR 中读取预设的内核栈指针)。
|
||||
- 把返回地址(下一条指令)和标志寄存器保存到特定寄存器(如 `rcx`、`r11`),然后跳转到内核预先设置好的**入口函数**。
|
||||
3. **内核软处理**
|
||||
入口函数将刚才没来得及保存的全部寄存器压入内核栈(形成 `pt_regs` 结构),然后根据**系统调用号**(放在 `rax` 通用寄存器中)从系统调用表里找到对应的内核函数(如 `ksys_read`)并执行。
|
||||
4. **内核执行 & 返回**
|
||||
内核函数完成实际工作(检查权限、读取数据等),把结果放在 `rax` 通用寄存器中。返回前,内核检查是否有其他任务需要处理(如信号、调度),然后通过 `sysret` 指令恢复之前保存的寄存器、用户栈和返回地址,特权级自动切回 **Ring 3**,程序从当初的下一条指令继续运行。
|
||||
|
||||
123
note/资源/DevOps/vscode快捷键.md
Normal file
123
note/资源/DevOps/vscode快捷键.md
Normal file
@ -0,0 +1,123 @@
|
||||
配置文件位置
|
||||
|
||||
```
|
||||
C:\Users\admin\AppData\Roaming\Code\User\keybindings.json
|
||||
```
|
||||
|
||||
该文件保存的是用户级快捷键列表,每一个快捷键配置都是包含`key`、`command`、`when`(可选)字段
|
||||
|
||||
| 字段 | 作用 |
|
||||
| :------------ | :------------------------------- |
|
||||
| **`key`** | 你按下的键盘组合 |
|
||||
| **`command`** | 要执行的命令 ID |
|
||||
| **`when`** | 规定这条快捷键在什么“语境”下生效 |
|
||||
|
||||
完整示例:
|
||||
|
||||
```json
|
||||
// markdown 代码块
|
||||
{
|
||||
"key": "ctrl+shift+`",
|
||||
"command": "markdown.extension.editing.toggleCodeBlock",
|
||||
"when": "editorTextFocus && editorLangId == 'markdown'"
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 按键的书写规则
|
||||
|
||||
### 基本格式
|
||||
|
||||
- **全小写**:修饰键和字母键都要小写,写 `ctrl` 而不是 `Ctrl`,写 `a` 而不是 `A`。
|
||||
- **用 `+` 连接**:按键之间用加号连接,不带空格。例如 `ctrl+shift+a`。
|
||||
- **修饰键顺序任意**:`ctrl+alt+a` 和 `alt+ctrl+a` 效果相同,但习惯按 `ctrl -> shift -> alt -> 字母` 的顺序写
|
||||
|
||||
### 支持的修饰键
|
||||
|
||||
| 修饰键 | 写法 | 说明 |
|
||||
| :------------ | :------ | :---------------------------------------------- |
|
||||
| Ctrl | `ctrl` | Windows / Linux 上常用 `ctrl`,macOS 对应 `cmd` |
|
||||
| Shift | `shift` | |
|
||||
| Alt | `alt` | macOS 上是 `opt`(或者也支持 `alt`) |
|
||||
| Cmd (Mac) | `cmd` | 在 Windows 上无效,建议用 `ctrl` 兼顾跨平台 |
|
||||
| Win (Windows) | `win` | 很少用 |
|
||||
| Meta (macOS) | `meta` | 通常等同 `cmd` |
|
||||
|
||||
### 特殊按键名称
|
||||
|
||||
| 按键 | 写法 |
|
||||
| :----------- | :------------------------------------- |
|
||||
| 方向键 | `up` `down` `left` `right` |
|
||||
| 功能键 | `f1` ~ `f19` |
|
||||
| 回车 | `enter` |
|
||||
| 空格 | `space` |
|
||||
| 退格 | `backspace` |
|
||||
| Tab | `tab` |
|
||||
| 反引号 | ``` (就是 backtick) |
|
||||
| 逗号、句号 | `,` `.` 等直接写符号本身 |
|
||||
| 数字键 | `0`~`9` |
|
||||
| 计算器小键盘 | `numpad0` ~ `numpad9`,`numpad_add` 等 |
|
||||
|
||||
### 按键组合
|
||||
|
||||
VS Code 支持**二段按键**(一次按键序列),写法是:
|
||||
|
||||
```json
|
||||
"key": "ctrl+k ctrl+b"
|
||||
```
|
||||
|
||||
意思是先按 `Ctrl+K`,松开后再按 `Ctrl+B`。
|
||||
|
||||
## 命令ID
|
||||
|
||||
`command` 是一个**全局唯一的字符串**,由扩展或 VS Code 自己注册。不能自己编造,必须使用确切的 ID。
|
||||
|
||||
通过`ctrl+k ctrl+b`按键组合或者在设置中点击“键盘快捷方式”即可查看当前能设置的所有的命令。虽然显示的是命令,但是实际上是命令的名字,右键可以获取命令的ID。也可以不通过修改配置文件,在图形化界面设置快捷键。
|
||||
|
||||
|
||||
|
||||
## 上下文条件表达式
|
||||
|
||||
`when` 是一个**布尔表达式**,只有计算结果为 `true` 时,快捷键才会触发,可以组合变量使用逻辑运算符。
|
||||
|
||||
### 常用上下文变量
|
||||
|
||||
| 变量 | 说明 | 常见值 |
|
||||
| :------------------------------ | :------------------------------------------------- | :------------------------------------------ |
|
||||
| `editorTextFocus` | 焦点是否在编辑器的**文本区域**(光标可以输入文字) | `true` / `false` |
|
||||
| `editorLangId` | 当前编辑器的语言 ID(不是文件后缀) | `"markdown"`, `"javascript"`, `"python"` 等 |
|
||||
| `editorHasSelection` | 编辑器里是否有文本被选中 | `true` / `false` |
|
||||
| `isLinux`, `isWindows`, `isMac` | 当前操作系统 | `true` / `false` |
|
||||
| `resourceExtname` | 当前文件的后缀名(带`.`) | `".md"`, `".js"` 等 |
|
||||
| `activeEditor` | 是否有激活的编辑器 | `true` / `false` |
|
||||
| `terminalFocus` | 焦点是否在集成终端 | `true` / `false` |
|
||||
| `listFocus` | 焦点在列表/树视图吗 | `true` / `false` |
|
||||
|
||||
### 逻辑运算符
|
||||
|
||||
| 运算符 | 含义 |
|
||||
| :--------- | :----------------------------------------------------------- |
|
||||
| `&&` | 与 |
|
||||
| ` | |
|
||||
| `!` | 非 |
|
||||
| `==`, `!=` | 等于 / 不等于(字符串) |
|
||||
| `=~` | 正则匹配(例如:`editorLangId =~ /^markdown$ |
|
||||
| `in` | 测试左侧值是否在给定的右值数组里,如 `editorLangId in ['markdown', 'rmd']` |
|
||||
|
||||
### 例子分析
|
||||
|
||||
```json
|
||||
"when": "editorTextFocus && editorLangId == 'markdown'"
|
||||
```
|
||||
|
||||
表达式含义:确保你正在编辑文本,而不是在侧边栏、终端或其他地方**并且**当前文件被 VS Code 识别为 Markdown 语言
|
||||
|
||||
## 常见问题排查
|
||||
|
||||
| 现象 | 可能原因 |
|
||||
| :------------------------------- | :------------------------------------------------------ |
|
||||
| 按键完全没反应 | `command` 拼写错误;`when` 条件一直为 false;扩展未激活 |
|
||||
| 在其他语言文件里也生效了 | 缺少 `editorLangId == 'xxx'` 限制,考虑加上 |
|
||||
| 一次性按了没反应,但按键序列可以 | 可能你定义成了 chord,但习惯是单键 |
|
||||
| 提示 “command 'xxx' not found” | 命令 ID 不存在,检查扩展是否已安装并启用 |
|
||||
1661
note/资源/命理/塔罗牌.md
Normal file
1661
note/资源/命理/塔罗牌.md
Normal file
File diff suppressed because it is too large
Load Diff
225
note/资源/命理/小六壬.md
Normal file
225
note/资源/命理/小六壬.md
Normal file
@ -0,0 +1,225 @@
|
||||
### **小六壬时课 · 知识库**
|
||||
|
||||
#### **一、 简介:什么是小六壬?**
|
||||
|
||||
小六壬,相传为三国时期诸葛亮、唐代李淳风所创,是一种简便、快速的预测方法,因其起课方便、便于携带(仅需掐指一算),故有“袖珍式预测学”或“马前课”之称。
|
||||
|
||||
其核心思想是,根据事发或问事时的“时间”或“心念”所触发的即时信息,来推演事物的状态和发展趋势。它主要用于对**单一、具体、短期**的事情进行快速占断,属于“一事一占”的动念占法。
|
||||
|
||||
**核心特点**:
|
||||
|
||||
- **简便快捷**:无需复杂工具,仅凭掌诀即可推算。
|
||||
- **随机性强**:动念即可成课,捕捉瞬间天机。
|
||||
- **应用广泛**:适用于寻物、问事、决疑、出行等日常生活的方方面面。
|
||||
|
||||
#### **二、 核心概念:六神宫位与掌诀**
|
||||
|
||||
小六壬共有六个基本“角色”,称为“六神”(或六宫),它们分布在食指、中指和无名指的指节上,形成一个固定的“掌上地盘”,即“掌诀”。
|
||||
|
||||
**掌诀位置图示**: 您可以伸出左手,按照下图在手指上定位六神:
|
||||
|
||||
- **大安**:食指根部
|
||||
- **留连**:食指尖部
|
||||
- **速喜**:中指尖部
|
||||
- **赤口**:无名指尖部
|
||||
- **小吉**:无名指根部
|
||||
- **空亡**:中指根部
|
||||
|
||||
(其顺序为顺时针循环)
|
||||
|
||||
**六神基础信息表**:
|
||||
|
||||
| 宫位/六神 | 五行 | 吉凶 | 核心意象与关键词 |
|
||||
| :------------------ | :--- | :--- | :--------------------------------- |
|
||||
| **大安 (Dà'ān)** | 木 | 吉 | 安泰、平稳、静止、官方、身体、龙 |
|
||||
| **留连 (Liúlián)** | 水 | 凶 | 延迟、纠缠、牵绊、缓慢、暧昧、暗昧 |
|
||||
| **速喜 (Sùxǐ)** | 火 | 吉 | 快速、喜讯、文书、宴饮、光明、朱雀 |
|
||||
| **赤口 (Chìkǒu)** | 金 | 凶 | 口舌、官非、争斗、惊恐、凶险、白虎 |
|
||||
| **小吉 (Xiǎojí)** | 木 | 吉 | 合作、财利、和合、顺畅、六合 |
|
||||
| **空亡 (Kōngwáng)** | 土 | 凶 | 落空、无果、忧虑、阴私、迷茫、玄武 |
|
||||
|
||||
#### **三、 主要起课方法**
|
||||
|
||||
起课,就是根据参数确定最终落在哪一个宫位上。
|
||||
|
||||
**1. 传统时间起课法(月、日、时)** 这是最正统的方法,以农历时间为准。
|
||||
|
||||
- 第一步:月上起日
|
||||
- 从**大安**宫开始,顺时针将月份数代入。例如,一月为大安,二月为留连,三月为速喜……以此类推。
|
||||
- 第二步:日上起时
|
||||
- 从上一步月份的落宫开始,顺时针将日期数(初一、初二……)代入。
|
||||
- 第三步:时上定宫
|
||||
- 从上一步日期的落宫开始,顺时针将时辰数(子时为1,丑时为2……)代入,最终落下的宫位即为结果。
|
||||
|
||||
**【示例】**:占测农历八月初十下午4点(申时)。
|
||||
|
||||
1. **定月**:从大安宫数8个月,落点在**赤口**。(1大安→2留连→3速喜→4赤口→5小吉→6空亡→7大安→8赤口)
|
||||
|
||||
2. **定日**:从赤口宫数10日,落点在**小吉**。(1小吉→2空亡→...→6赤口→...→10小吉)
|
||||
|
||||
3. 定时
|
||||
|
||||
:申时是第9个地支。从上一步的小吉宫数9个时辰,最终落点在
|
||||
|
||||
速喜
|
||||
|
||||
。
|
||||
|
||||
- **结果**:速喜。
|
||||
|
||||
**2. 报数起课法** 当不知晓具体时辰或为求心念感应时使用。
|
||||
|
||||
- 让问事者随意报出**三个数字**(1位数到3位数均可)。
|
||||
- 将每个数字分别**除以6,取其余数**(若余数为0,则按6计算)。
|
||||
- **第一步**:从“大安”宫起,按第一个余数顺时针数,定下基点。
|
||||
- **第二步**:从基点宫位起,按第二个余数顺时针数,定下过程点。
|
||||
- **第三步**:从过程点起,按第三个余数顺时针数,定下最终结果。
|
||||
|
||||
**【示例】**:报数为 7, 11, 32。
|
||||
|
||||
1. **第一数**:`7 ÷ 6 = 1 ... 余 1`。从大安数1,落在**大安**。
|
||||
|
||||
2. **第二数**:`11 ÷ 6 = 1 ... 余 5`。从大安数5,落在**小吉**。
|
||||
|
||||
3. 第三数
|
||||
|
||||
:
|
||||
|
||||
```
|
||||
32 ÷ 6 = 5 ... 余 2
|
||||
```
|
||||
|
||||
。从小吉数2,落在
|
||||
|
||||
空亡
|
||||
|
||||
。
|
||||
|
||||
- **结果**:空亡。
|
||||
|
||||
#### **四、 六神象义详解与分类占断**
|
||||
|
||||
这是解卦的核心,需要结合所问之事灵活判断。
|
||||
|
||||
**1. 大安**
|
||||
|
||||
- **核心**:身不动,心安宁。静待为吉,妄动有失。
|
||||
- **问事**:事可成,但需时日,不可急躁。过程平顺。
|
||||
- **寻物/寻人**:人或物未走远,在家中或原地,或在东方、东北方,多在静态、稳定的环境中(如办公室、卧室)。
|
||||
- **感情**:关系稳定,感情安泰,但可能缺乏激情。
|
||||
- **财运**:财运稳定,宜守成,不宜投机。
|
||||
- **健康**:身体安康,即使有病也易于恢复。
|
||||
|
||||
**2. 留连**
|
||||
|
||||
- **核心**:事未了,心纠结。拖延、纠缠、暧昧不清。
|
||||
- **问事**:事情进展缓慢,有阻碍,难以立刻解决,容易节外生枝。
|
||||
- **寻物/寻人**:难寻,或被某事/某人牵绊住。物品可能在潮湿、脏乱或纠缠之地。
|
||||
- **感情**:关系纠缠不清,或处于冷战、延迟状态。有藕断丝连之象。
|
||||
- **财运**:财运不畅,资金周转困难,或有债务纠纷。
|
||||
- **健康**:病情迁延,难以速愈,多为慢性病或旧病复发。
|
||||
|
||||
**3. 速喜**
|
||||
|
||||
- **核心**:火光之象,喜信速至。宜速战速决,不宜拖延。
|
||||
- **问事**:事能速成,有喜讯或好结果。尤其利于文书、考试、信息类事宜。
|
||||
- **寻物/寻人**:能快速找到。人或物在南方,或在热闹、明亮之处。
|
||||
- **感情**:进展神速,热情洋溢,或有喜事临门(如订婚、结婚)。
|
||||
- **财运**:偏财运旺,有意外之财,或短期投资获利。
|
||||
- **健康**:多为急症、热症(如发烧、炎症),但来得快去得也快。
|
||||
|
||||
**4. 赤口**
|
||||
|
||||
- **核心**:白虎开口,是非官讼。主凶险、争斗、惊扰。
|
||||
- **问事**:事多纷争,易有口舌是非,甚至官司诉讼。过程不顺,需防小人。
|
||||
- **寻物/寻人**:难寻。多有争吵或处于危险境地。物品可能已损坏。
|
||||
- **感情**:关系紧张,争吵频繁,易有分离之象。
|
||||
- **财运**:破财之象,谨防因纠纷、官非而损财。
|
||||
- **健康**:需防意外伤害、手术、或急性恶疾。有血光之灾的警示。
|
||||
|
||||
**5. 小吉**
|
||||
|
||||
- **核心**:六合之象,诸事和合。代表合作、财利、转机。
|
||||
- **问事**:事情顺利,有贵人相助,适宜合作、商议。
|
||||
- **寻物/寻人**:易寻。人或物在附近,或与友人、同伴在一起。
|
||||
- **感情**:关系和谐,琴瑟和鸣,是发展的良好时机。
|
||||
- **财运**:正财、合伙之财运佳,交易顺利。
|
||||
- **健康**:病情好转,遇到良医,康复有望。
|
||||
|
||||
**6. 空亡**
|
||||
|
||||
- **核心**:万事成空,虚无之象。信息不实,劳而无功。
|
||||
- **问事**:事情没有头绪,心中没底,最终可能不了了之或毫无结果。有虚假、欺骗的成分。
|
||||
- **寻物/寻人**:人已远去,物已丢失,找回希望渺茫。
|
||||
- **感情**:关系空虚,前景不明,或对方心意不诚。
|
||||
- **财运**:财运空空,投资无望,谨防被骗。
|
||||
- **健康**:病情诊断不明,或查无此症,也可能指精神、心理层面的问题。
|
||||
|
||||
#### **五、 断辞内容**
|
||||
|
||||
1、大安:身不动时,属木,为青龙,凡谋事主一、五、七。
|
||||
|
||||
断辞曰:
|
||||
|
||||
大安事事昌,求谋在东方,失物去不远,
|
||||
|
||||
宅舍保安康,行人身未动,病者主无妨,
|
||||
|
||||
将军回田野,仔细与推详。
|
||||
|
||||
2、留连:卒未归时,属水,为玄武,凡谋事主二、八、十。
|
||||
|
||||
断辞曰:
|
||||
|
||||
留连事难成,求谋曰未明,官事只宜缓,
|
||||
|
||||
去者未回程,失物南方见,急讨方称心,
|
||||
|
||||
更须防口舌,人口且平平。
|
||||
|
||||
3、速喜:人便至时,属火,为朱雀,凡谋事主三、六、九。
|
||||
|
||||
断辞曰:
|
||||
|
||||
速喜喜来临,求财向南行,失物申午未,
|
||||
|
||||
逢人路上寻,官事有福德,病者无祸侵,
|
||||
|
||||
田家六畜吉,行人有信音。
|
||||
|
||||
4、赤口:官事凶时,属金,为白虎,凡谋事主四、七、十。
|
||||
|
||||
断辞曰:
|
||||
|
||||
赤口主口舌,官非切要防,失物急去寻,
|
||||
|
||||
行人有惊慌,鸡犬多作怪,病者出西方,
|
||||
|
||||
更须防咒诅,恐怕染蕴疾。
|
||||
|
||||
5、小吉:人来喜时,属木,为六合,凡谋事主一、五、七。
|
||||
|
||||
断辞曰:
|
||||
|
||||
小吉最吉昌,路上好商良,阳人来报喜,
|
||||
|
||||
失物在坤方,行人立便至,交关真是强,
|
||||
|
||||
凡事皆和合,病者事无仿。
|
||||
|
||||
6、空亡:音信稀时,属土,为勾陈,凡谋事主一、五、七。
|
||||
|
||||
断辞曰:
|
||||
|
||||
空亡事不长,阴人小乘张,求财无有利,
|
||||
|
||||
行人有灾殃,失物寻不见,官事主刑伤,
|
||||
|
||||
病人逢暗鬼,乞解保安康。
|
||||
|
||||
#### **六、 使用原则与心法**
|
||||
|
||||
- **心诚意专**:占测时心态必须虔诚、专注,意念集中于所问之事。
|
||||
- **一事一占**:同一件事在短期内不应反复占问,以第一次的结果为准。所谓“再三渎,渎则不告”。
|
||||
- **动念即占**:当某个问题或念头强烈地出现在脑海中时,是最佳的占测时机。
|
||||
- **趋吉避凶**:小六壬提供的是一种预警和参考。得到吉卦,应顺势而为;得到凶卦,则应反思、谨慎、规避,而非坐以待毙。它是一种积极的“行为指导”,而非消极的“宿命论”。
|
||||
21
note/资源/数据库/SQL/函数.md
Normal file
21
note/资源/数据库/SQL/函数.md
Normal file
@ -0,0 +1,21 @@
|
||||
## CONCAT函数
|
||||
|
||||
`CONCAT` 是 SQL 中用于**字符串拼接**的函数,它可以将两个或多个字符串合并成一个新的字符串。
|
||||
|
||||
------
|
||||
|
||||
### 基本语法
|
||||
|
||||
```sql
|
||||
CONCAT(string1, string2, ..., stringN)
|
||||
```
|
||||
|
||||
### 不同数据库的 CONCAT 行为
|
||||
|
||||
| 数据库 | 行为 |
|
||||
| :--------------------- | :----------------------------------------------- |
|
||||
| **MySQL** | 支持多参数;**任一参数为 NULL,整个结果为 NULL** |
|
||||
| **SQL Server** (2012+) | 支持多参数;**NULL 会被自动转为空字符串** `''` |
|
||||
| **Oracle** | 只支持 **2 个参数**;NULL 视为空字符串 |
|
||||
| **PostgreSQL** | 支持多参数;NULL 视为空字符串 |
|
||||
|
||||
44
note/资源/数据库/SQL/索引.md
Normal file
44
note/资源/数据库/SQL/索引.md
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
|
||||
## B-Tree
|
||||
|
||||
**适用场景**
|
||||
|
||||
| 场景 | 示例 |
|
||||
| :------- | :-------------------------- |
|
||||
| 等值查询 | WHERE user_id = 100 |
|
||||
| 范围查询 | WHERE age BETWEEN 20 AND 30 |
|
||||
| 排序优化 | ORDER BY created_at DESC |
|
||||
| 前缀匹配 | WHERE name LIKE '张%' |
|
||||
|
||||
**不适用场景**
|
||||
|
||||
- LIKE '%关键词%'(后缀/中间模糊匹配)
|
||||
|
||||
- 全文搜索
|
||||
|
||||
- 数组包含查询
|
||||
|
||||
|
||||
|
||||
## GIN
|
||||
|
||||
**结构特点**
|
||||
|
||||
- 倒排索引(Inverted Index) 机制:从"内容"映射到"行"
|
||||
|
||||
- 索引的是复合值内部的独立元素
|
||||
|
||||
- 索引构建较慢,但查询性能极佳
|
||||
|
||||
**适用场景**
|
||||
|
||||
> `@>`表示包含、`<@`表示被包含、`&&`表示重叠、`@@`表示全文搜索匹配、`?`表示JSONB 键存在
|
||||
|
||||
| 场景 | 示例 |
|
||||
| :----------- | :----------------------------------------------------- |
|
||||
| 全文搜索 | WHERE to_tsvector(content) @@ to_tsquery('postgresql') |
|
||||
| 数组包含 | WHERE tags @> ARRAY['java', 'sql'] |
|
||||
| JSONB 查询 | WHERE data @> '{"status": "active"}' |
|
||||
| 多值元素搜索 | WHERE arr && ARRAY[1, 2] |
|
||||
|
||||
60
note/资源/算法/抽奖算法.md
Normal file
60
note/资源/算法/抽奖算法.md
Normal file
@ -0,0 +1,60 @@
|
||||
## 权重抽奖
|
||||
|
||||
### 轮盘赌
|
||||
|
||||
适合奖品数量较少,一次性抽奖的场景
|
||||
|
||||
核心顺序遍历,逐个减权重:是用一个随机数 `r`,依次减去每个奖品的权重,当 `r` 变成负数的那一刻,说明它“落入了”当前奖品的权重区间。时间复杂度 **O(n)**,空间复杂度**O(1)**
|
||||
|
||||
```go
|
||||
func Draw(rewards []*Reward) *Reward {
|
||||
totalWeight := 0
|
||||
for _, r := range rewards {
|
||||
totalWeight += r.Weight
|
||||
}
|
||||
r := rand.Intn(totalWeight) // [0, totalWeight)
|
||||
for _, reward := range rewards {
|
||||
r -= reward.Weight
|
||||
if r < 0 {
|
||||
return reward
|
||||
}
|
||||
}
|
||||
return rewards[len(rewards)-1] // 兜底,理论上不会走到
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 前缀和 + 二分查找
|
||||
|
||||
适合奖品数量较多,需要频繁抽奖的通用场景
|
||||
|
||||
核心是构建前缀和数组,二分查找:把权重想象成一条线段,每个奖品占据一段,生成 `[0, 100)` 的随机数,落在哪个区间就中哪个奖品。二分查找快速定位区间,时间复杂度 **O(log n)**,空间复杂度**O(n)**
|
||||
|
||||
```
|
||||
权重: 50 25 15 7 2 1
|
||||
├─────────┼────────┼──────┼────┼──┼──┤
|
||||
0 50 75 90 97 99 100
|
||||
← 谢谢参与 →←5元券→←10元券→←月卡→←年卡→←大奖→
|
||||
```
|
||||
|
||||
```go
|
||||
type Reward struct {
|
||||
Name string
|
||||
Weight int
|
||||
}
|
||||
|
||||
func Draw(rewards []*Reward) *Reward {
|
||||
prefixSumArray := make([]int, len(rewards)) // 前缀和数组
|
||||
totalWeight := 0 // 总权重
|
||||
for i, p := range rewards {
|
||||
totalWeight += p.Weight
|
||||
prefixSumArray[i] = totalWeight
|
||||
fmt.Println(totalWeight)
|
||||
}
|
||||
r := rand.Intn(totalWeight) // r ∈ [0, totalWeight-1]
|
||||
idx := sort.SearchInts(prefixSumArray, r+1) // 查找目标 ∈ [1, totalWeight]
|
||||
return rewards[idx]
|
||||
}
|
||||
```
|
||||
|
||||
123
note/资源/编程/Golang/go-zero/goctl.md
Normal file
123
note/资源/编程/Golang/go-zero/goctl.md
Normal file
@ -0,0 +1,123 @@
|
||||
## API
|
||||
|
||||
### goctl代码生成
|
||||
|
||||
可以在doc/genCode.md查看
|
||||
|
||||
```powershell
|
||||
# 生成多个types类型的话需要关闭这个实验性功能
|
||||
goctl env -w GOCTL_EXPERIMENTAL=off
|
||||
|
||||
# 代码生成,会自动处理引入的子api文件
|
||||
goctl api go -api background.api -dir . --home D:/zhangyuxin/template/1.8.3
|
||||
goctl api go -api login.api -dir . --home ../../../deploy/goctl
|
||||
goctl api go -api main.api -dir . --home ../../deploy/goctl
|
||||
```
|
||||
|
||||
### 参数校验
|
||||
|
||||
| 接收规则 | 说明 | 示例 |
|
||||
| -------- | ------------------------------------------ | ------------------------------- |
|
||||
| optional | 当前字段是可选参数,允许为零值(zero value) | `json:"foo,optional"` |
|
||||
| options | 当前参数仅可接收的枚举值 | `json:"gender,options=foo|bar"` |
|
||||
| default | 当前参数默认值 | `json:"gender,default=male"` |
|
||||
| range | 当前参数数值有效范围,支持开/闭区间 | `json:"age,range=[0:120]"` |
|
||||
|
||||
#### **`optional`** **与** **`omitempty`** **的区别**
|
||||
|
||||
两者都写在 json/form tag 的 options 里,但作用域完全不同,不可互相替代
|
||||
|
||||
##### `optional` —— goctl 专用,控制 Swagger 与请求校验
|
||||
|
||||
- **Swagger 生成**:标了 `optional` 的字段不进 `required` 数组,Apifox/Swagger UI 显示为可选;未标的字段进 `required` 数组,显示为必填
|
||||
- **请求校验**:goctl 生成的 logic 不会对标了 `optional` 的字段做必填校验
|
||||
- **判定逻辑**:goctl 遍历 tag options,找到 `optional` 关键字即判定为可选
|
||||
|
||||
##### `omitempty` —— Go 标准库指令,控制 JSON 序列化
|
||||
|
||||
- **JSON 序列化**:字段为零值(0、""、nil、false)时,响应 JSON 中**不输出**该字段
|
||||
- **Swagger 生成**:**goctl 完全不识别**,字段仍按未标 `optional` 处理,即判定为 required
|
||||
- **请求校验**:无影响
|
||||
|
||||
## RPC
|
||||
|
||||
### goctl代码生成
|
||||
|
||||
```powershell
|
||||
# 主proto文件代码生成
|
||||
goctl rpc protoc user.proto --go_out=. --go-grpc_out=. --zrpc_out=. --proto_path=. -m --home ../../../deploy/goctl
|
||||
|
||||
# 主proto文件中引入的proto代码生成
|
||||
protoc.exe -I ./ --go_out=. --go-grpc_out=. ./user_model.proto
|
||||
|
||||
```
|
||||
|
||||
当`proto`文件里面定义了多个 service的时候,需要额外注意,还要再main函数中手动注册一下
|
||||
|
||||
> 每个 proto 文件应该聚焦于一个核心概念/实体。一个文件里定义太多 service 通常是设计需要重新考虑的信号
|
||||
|
||||
注册示例
|
||||
|
||||
```go
|
||||
import (
|
||||
ebookServer "olive/services/product/rpc/internal/server/ebookservice"
|
||||
)
|
||||
|
||||
var configFile = flag.String("f", "etc/product.yaml", "the config file")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var c config.Config
|
||||
conf.MustLoad(*configFile, &c)
|
||||
ctx := svc.NewServiceContext(c)
|
||||
|
||||
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
||||
// 新服务
|
||||
productrpcmodel.RegisterEbookServiceServer(grpcServer, ebookServer.NewEbookServiceServer(ctx))
|
||||
})
|
||||
defer s.Stop()
|
||||
|
||||
fmt.Printf("Starting product RPC server at %s...\n", c.ListenOn)
|
||||
s.Start()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### proto代码生成错误:File not found错误
|
||||
|
||||
- 错误描述
|
||||
|
||||
执行 protoc 报 google/protobuf/timestamp.proto: File not found. 的错提示File not found
|
||||
|
||||
- 解决方式
|
||||
|
||||
重新下载[protoc](https://github.com/protocolbuffers/protobuf/releases),解压后,将整个include目录复制到protoc执行文件同一级目录下
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## model
|
||||
|
||||
可以在doc/genCode.md查看
|
||||
|
||||
**Model 层**:只做 **“业务循环”** + **“SQL 查询”** + **“结果封装”**,不关心字符串到时间的转换和 Protobuf 类型。
|
||||
|
||||
### goctl代码生成
|
||||
|
||||
```powershell
|
||||
# mysql根据远程数据库表生成
|
||||
goctl model mysql datasource --url="olive:xxvkikaDDx01&&99@tcp(127.0.0.1:3306)/ebming" --table="user_invitation_record" --dir="." -c --home ../../../../deploy/goctl/1.8.3
|
||||
|
||||
# mysql根据ddl生成
|
||||
goctl model mysql ddl --src h5.sql --dir . -c --home D:/zhangyuxin/template/1.8.3
|
||||
|
||||
# pgsql根据远程数据库表生成
|
||||
goctl model pg datasource -url "postgres://labman:tN5bWz2KpL9Fy4@127.0.0.1:15432/sern" -table user -dir ./user --cache --home ../../goctl_template/1.8.3
|
||||
|
||||
# pgsql根据远程数据库表生成,带模式(schema)
|
||||
goctl model pg datasource -url "postgres://admin:zhangyuxin@127.0.0.1:25432/test?sslmode=disable" -s "users" -table "profile" -dir ./go-zero/model/users/ --cache --home ../../deploy/goctl
|
||||
```
|
||||
|
||||
212
note/资源/编程/Golang/使用注意.md
Normal file
212
note/资源/编程/Golang/使用注意.md
Normal file
@ -0,0 +1,212 @@
|
||||
|
||||
|
||||
## 正确关闭`HTTP`响应
|
||||
|
||||
> **注意事项**
|
||||
>
|
||||
> - 先检查 `err`,再 `defer close`
|
||||
>
|
||||
> - 必须消费完响应体,否则连接无法复用
|
||||
>
|
||||
> - `defer` 会延迟到函数结束,如果需要在循环中处理大量响应,建议手动关闭(避免 `defer` 累积)
|
||||
|
||||
```go
|
||||
resp, err := http.Get("https://example.com")
|
||||
if err != nil {
|
||||
// 处理请求错误(此时 resp 可能为 nil)
|
||||
return err
|
||||
}
|
||||
// 确保在函数退出时关闭响应体
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 手动关闭,不用 defer
|
||||
// io.Copy(io.Discard, resp.Body)
|
||||
// resp.Body.Close()
|
||||
|
||||
// 读取或处理响应体(即使不需要内容也建议消费完)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 使用 body ...
|
||||
```
|
||||
|
||||
## 切片内存泄漏
|
||||
|
||||
> 即使原切片变量本身被置为 `nil` 或超出作用域,只要**还存在任何一个指向其底层数组的子切片**,整个底层数组就不会被回收
|
||||
|
||||
如果新切片需要长期保存,而原切片很大且即将被丢弃,那么**直接使用原切片[:n] 会导致新切片底层仍然引用原切片的整个底层数组**,使得那个大数组无法被 GC 回收,造成内存泄漏。此时应该用 `copy` 创建一份独立的、只包含所需元素的新切片。
|
||||
|
||||
```go
|
||||
func getFirstLines() []string {
|
||||
hugeLines := readHugeFile() // 假设这个切片有 100 万行,占用 100MB 内存
|
||||
// 错误做法:返回子切片
|
||||
return hugeLines[:3] // 虽然只返回3行,但底层数组的 100MB 内存无法被回收!
|
||||
}
|
||||
|
||||
// 正确做法
|
||||
func getFirstLines() []string {
|
||||
hugeLines := readHugeFile()
|
||||
// 只拷贝需要的3行
|
||||
result := make([]string, 3)
|
||||
copy(result, hugeLines[:3])
|
||||
return result // 原来的 hugeLines 可以被GC回收,只占用很小的内存
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 堆栈
|
||||
|
||||
### 核心区别
|
||||
|
||||
| 特性 | 栈 | 堆 |
|
||||
| --------- | -------------- | ------------------ |
|
||||
| 分配/释放 | 移动指针,极快 | 需要查找 + GC 回收 |
|
||||
| 生命周期 | 函数返回即销毁 | GC 决定何时回收 |
|
||||
| 内存布局 | 连续,无碎片 | 分散,有碎片 |
|
||||
| 大小限制 | 较小(MB级) | 较大(GB级) |
|
||||
|
||||
### 逃逸判断规则
|
||||
|
||||
```
|
||||
变量在以下情况逃逸到堆:
|
||||
|
||||
1. 返回指针 → func f() *int { x := 42; return &x }
|
||||
2. 存入全局变量 → globalPtr = &x
|
||||
3. 闭包捕获 → return func() { return x }
|
||||
4. 发送到 channel → ch <- &x
|
||||
5. 存入外部结构体 → c.Value = &x
|
||||
6. 接口装箱逃逸 → return interface{}(x)
|
||||
7. 反射调用 → fmt.Println(x)
|
||||
8. 大对象 → make([]int, 10000)
|
||||
```
|
||||
|
||||
### 常见误区澄清
|
||||
|
||||
| 误区 | 正解 |
|
||||
| ------------------ | -------------------------------- |
|
||||
| 指针一定在堆上 | ❌ 函数内创建和使用的指针可在栈上 |
|
||||
| 接口一定在堆上 | ❌ 不逃逸的接口内部值可在栈上 |
|
||||
| 结构体指针一定逃逸 | ❌ 小结构体 + 内联优化可能栈分配 |
|
||||
|
||||
### 验证方法
|
||||
|
||||
```bash
|
||||
# 查看逃逸分析
|
||||
go build -gcflags="-m" main.go
|
||||
|
||||
# 更详细信息
|
||||
go build -gcflags="-m -m" main.go
|
||||
```
|
||||
|
||||
### 优化建议
|
||||
|
||||
```go
|
||||
// ✅ 推荐:小对象返回值
|
||||
func getUser() User {
|
||||
return User{
|
||||
ID: 1
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ 避免:小对象返回指针(增加 GC 压力)
|
||||
func getUser() *User {
|
||||
return &User{
|
||||
ID: 1
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 推荐:传指针给只读函数
|
||||
func read(p *Data) int {
|
||||
return p.Value
|
||||
}
|
||||
|
||||
// ❌ 避免:在热路径使用 fmt.Print
|
||||
// 用 strconv 或 log 代替
|
||||
```
|
||||
|
||||
### 记忆口诀
|
||||
|
||||
```
|
||||
生命周期越界 → 堆
|
||||
外部有引用 → 堆
|
||||
闭包捕获 → 堆
|
||||
反射调用 → 堆
|
||||
|
||||
函数内使用 → 栈
|
||||
返回值拷贝 → 栈
|
||||
只读指针 → 栈
|
||||
```
|
||||
|
||||
### 本质理解
|
||||
|
||||
**栈** = 函数的私有工作区,函数结束自动清理
|
||||
|
||||
**堆** = 共享仓库,需要 GC 定期打扫
|
||||
|
||||
逃逸分析 = 编译器判断"这个变量能不能安全地放在栈上"
|
||||
|
||||
|
||||
|
||||
## 类型转换/序列化
|
||||
|
||||
```
|
||||
//int64转换string
|
||||
strconv.FormatInt(num,10)
|
||||
|
||||
//序列化为string
|
||||
jsoniter.ConfigCompatibleWithStandardLibrary.MarshalToString(input)
|
||||
```
|
||||
|
||||
在 encode/decode JSON 数据并且数据类型是interface时,Go 默认会将数值当做 float64 处理
|
||||
|
||||
```go
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
Height float64 `json:"height"`
|
||||
}
|
||||
type UserInter struct {
|
||||
Name interface{} `json:"name"`
|
||||
Age interface{} `json:"age"`
|
||||
Height interface{} `json:"height"`
|
||||
}
|
||||
|
||||
func TestJson(t *testing.T) {
|
||||
one := &User{
|
||||
Name: "tom",
|
||||
Age: 18,
|
||||
}
|
||||
oneJson, err := jsoniter.Marshal(one)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
var two UserInter
|
||||
var three map[string]interface{}
|
||||
err = jsoniter.Unmarshal(oneJson, &two)
|
||||
err = jsoniter.Unmarshal(oneJson, &three)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(reflect.TypeOf(two.Name))
|
||||
fmt.Println(reflect.TypeOf(two.Age)) //会打印float64
|
||||
fmt.Println(reflect.TypeOf(two.Height)) //会打印float64
|
||||
fmt.Println(reflect.TypeOf(three["name"]))
|
||||
fmt.Println(reflect.TypeOf(three["age"])) //会打印float64
|
||||
fmt.Println(reflect.TypeOf(three["height"])) //会打印float64
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## `HTTP`阅后即焚
|
||||
|
||||
处理 HTTP Body 只能读一次的问题时,根据你的**数据量大小**选择武器:
|
||||
|
||||
1. **小请求(配置、JSON)**:使用 `io.ReadAll` 存入内存,再通过 `io.NopCloser` 塞回 `r.Body` 或设置 `r.GetBody`。
|
||||
2. **中等请求(签名校验)**:使用 `io.TeeReader` 边读边处理,节省一次全量扫描。
|
||||
3. **大请求(文件上传)**:**禁止 ReadAll**。直接流式 `io.Copy` 到目的地,或使用临时文件做中转。
|
||||
55
note/资源/编程/Golang/常用命令.md
Normal file
55
note/资源/编程/Golang/常用命令.md
Normal file
@ -0,0 +1,55 @@
|
||||
## 交叉编译
|
||||
|
||||
### 基本用法
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
GOOS=目标系统 GOARCH=目标架构 go build -o 输出文件名 源文件
|
||||
|
||||
# Windows (PowerShell)
|
||||
$env:GOOS="目标系统"; $env:GOARCH="目标架构"; go build -o 输出文件名 源文件
|
||||
|
||||
# Windows (CMD)
|
||||
set GOOS=目标系统 && set GOARCH=目标架构 && go build -o 输出文件名 源文件
|
||||
|
||||
```
|
||||
|
||||
查看所有支持的平台
|
||||
|
||||
```bash
|
||||
go tool dist list
|
||||
```
|
||||
|
||||
### 常用组合
|
||||
|
||||
| 目标平台 | GOOS | GOARCH |
|
||||
| ------------ | ------- | ------ |
|
||||
| Linux 64位 | linux | amd64 |
|
||||
| Linux ARM64 | linux | arm64 |
|
||||
| Windows 64位 | windows | amd64 |
|
||||
| macOS Intel | darwin | amd64 |
|
||||
| macOS M1/M2 | darwin | arm64 |
|
||||
|
||||
### 示例
|
||||
|
||||
```bash
|
||||
# Linux/Mac (Bash)
|
||||
# 编译 Linux 64位
|
||||
GOOS=linux GOARCH=amd64 go build -o app ./app/api/main.go
|
||||
# 编译 Windows 64位
|
||||
GOOS=windows GOARCH=amd64 go build -o app.exe ./app/api/main.go
|
||||
# 编译 macOS ARM64 (M1/M2)
|
||||
GOOS=darwin GOARCH=arm64 go build -o app ./app/api/main.go
|
||||
|
||||
# Windows (PowerShell)
|
||||
# 编译 Linux 64位
|
||||
$env:GOOS="linux"; $env:GOARCH="amd64"; go build -o app ./app/api/main.go
|
||||
# 编译 Windows 64位
|
||||
$env:GOOS="windows"; $env:GOARCH="amd64"; go build -o app.exe ./app/api/main.go
|
||||
# 编译 macOS ARM64 (M1/M2)
|
||||
$env:GOOS="darwin"; $env:GOARCH="arm64"; go build -o app ./app/api/main.go
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
117
note/资源/编程/Golang/常用第三方库.md
Normal file
117
note/资源/编程/Golang/常用第三方库.md
Normal file
@ -0,0 +1,117 @@
|
||||
|
||||
|
||||
### validator
|
||||
|
||||
[GitHub地址](github.com/go-playground/validator)
|
||||
|
||||
包验证器,可以用于验证参数是否符合规则,比如下方的比较验证,还有其他可以查看网址的详细介绍
|
||||
go-zero自带的有校验器,可以使用
|
||||
|
||||
| Tag | Description |
|
||||
| ---- | --------------------- |
|
||||
| eq | Equals |
|
||||
| gt | Greater than |
|
||||
| gte | Greater than or equal |
|
||||
| lt | Less Than |
|
||||
| lte | Less Than or Equal |
|
||||
| ne | Not Equal |
|
||||
|
||||
|
||||
|
||||
### goverter
|
||||
|
||||
[GitHub地址](https://github.com/jmattheis/goverter)
|
||||
|
||||
类型转换器,可以用于类型的转换,比如下面的代码
|
||||
|
||||
```go
|
||||
func (l *CreatePopupLogic) CreatePopup(in *backgroundrpcmodel.ResPopup) (*backgroundrpcmodel.ResResult, error) {
|
||||
_, err := l.svcCtx.PopupModel.Insert(l.ctx, u.Convert.SysPopupR2S(in.Info))
|
||||
if err != nil {
|
||||
return nil, rerr.NewFromSQL(err)
|
||||
}
|
||||
return &backgroundrpcmodel.ResResult{
|
||||
Result: true,
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
使用
|
||||
|
||||
```
|
||||
goverter gen .
|
||||
```
|
||||
|
||||
|
||||
|
||||
### asynq
|
||||
|
||||
[GitHub网址](https://github.com/hibiken/asynq)
|
||||
|
||||
- 入队流程
|
||||
|
||||
```go
|
||||
payload := &jobtype.xxxPayload{}
|
||||
payloadByte, err := jsoniter.Marshal(payload)
|
||||
if err != nil {
|
||||
logt.Error("xxx jsoniter.Marshal err:", err)
|
||||
return nil, zerr.New(rescode.DataFormatConversionError)
|
||||
}
|
||||
_, err = l.svcCtx.AsynqClient.Enqueue(asynq.NewTask(jobtype.xxx, payloadBytes, asynq.Queue(consts.QueueLow)))
|
||||
if err != nil {
|
||||
logt.Error("xxx enqueue err:", err)
|
||||
return nil, zerr.New(rescode.EnqueueErr)
|
||||
}
|
||||
```
|
||||
|
||||
- 自行定义了队列优先级,在入队的时候可以加参数进行选择
|
||||
|
||||
```
|
||||
consts.QueueCritical: 6,
|
||||
consts.QueueDefault: 3,
|
||||
consts.QueueLow: 1,
|
||||
```
|
||||
|
||||
- 处理前流程(反序列化,获取数据)
|
||||
|
||||
```go
|
||||
var payload jobtype.xxx
|
||||
err := json.Unmarshal(task.Payload(), &payload)
|
||||
if err != nil {
|
||||
logt.Error("xxx unmarshal payload err:", err)
|
||||
return zerr.New(rescode.DataFormatConversionError)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### gorm
|
||||
|
||||
[官网文档](https://gorm.io/zh_CN/docs/)
|
||||
|
||||
**使用gorm + sqlx,但是复用sql连接**
|
||||
|
||||
```go
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
logx.Infof("Cache config: %+v", c.CacheRedis)
|
||||
|
||||
gormDB, err := gorm.Open(postgres.Open(c.Database.DataSource), &gorm.Config{})
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("连接数据库失败 %s ", err.Error())
|
||||
logx.Error(msg)
|
||||
panic(msg)
|
||||
}
|
||||
sqlDB, err := gormDB.DB()
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("获取底层连接失败: %s", err.Error())
|
||||
logx.Error(msg)
|
||||
panic(msg)
|
||||
}
|
||||
sqlxConn := sqlx.NewSqlConnFromDB(sqlDB)
|
||||
return &ServiceContext{
|
||||
Config: c,
|
||||
UserAuthModel: models.NewUserAuthModel(sqlxConn, c.CacheRedis, gormDB),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
120
note/资源/网络/Restful.md
Normal file
120
note/资源/网络/Restful.md
Normal file
@ -0,0 +1,120 @@
|
||||
### URL设计规范
|
||||
|
||||
URL为统一资源定位器 ,接口属于服务端资源,通常一个完整的URL组成由以下几个部分构成:
|
||||
|
||||
```
|
||||
URI = scheme "://" host ":" port "/" path [ "?" query ][ "#" fragment ]
|
||||
```
|
||||
|
||||
- **scheme**: 指底层用的协议,如http、https、ftp
|
||||
- **host**: 服务器的IP地址或者域名
|
||||
- **port**: 端口,http默认为80端口
|
||||
- **path**: 访问资源的路径,就是各种web 框架中定义的route路由
|
||||
- **query**: 查询字符串,为发送给服务器的参数,在这里更多发送数据分页、排序等参数。
|
||||
- **fragment**: 锚点,定位到页面的资源
|
||||
|
||||
|
||||
|
||||
**通常一个RESTful API的path组成**如下:
|
||||
|
||||
```undefined
|
||||
/{version}/{resources}/{resource_id}
|
||||
```
|
||||
|
||||
- **version**:API版本号,有些版本号放置在头信息中也可以,通过控制版本号有利于应用迭代。
|
||||
- **resources**:资源,RESTful API推荐用小写英文单词的复数形式。
|
||||
- **resource_id**:资源的id,访问或操作该资源。
|
||||
|
||||
|
||||
|
||||
有时候可能资源级别较大,其下还可细分很多子资源也可以灵活设计URL的path,例如:
|
||||
|
||||
```undefined
|
||||
/{version}/{resources}/{resource_id}/{subresources}/{subresource_id}
|
||||
```
|
||||
|
||||
|
||||
|
||||
当增删改查无法满足业务要求,可以在URL末尾加上action,例如
|
||||
|
||||
```
|
||||
/{version}/{resources}/{resource_id}/action
|
||||
```
|
||||
|
||||
其中action就是对资源的操作。
|
||||
|
||||
|
||||
|
||||
**RESTful API的URL具体设计的规范**如下:
|
||||
|
||||
1. 不用大写字母,所有单词使用英文且小写。
|
||||
2. 连字符用中杠`"-"`而不用下杠`"_"`
|
||||
3. 正确使用 `"/"`表示层级关系,URL的层级不要过深,并且越靠前的层级应该相对越稳定
|
||||
4. 结尾不要包含正斜杠分隔符`"/"`
|
||||
5. URL中不出现动词,用请求方式表示动作
|
||||
6. 资源表示用复数不要用单数
|
||||
7. 不要使用文件扩展名
|
||||
|
||||
|
||||
|
||||
**[参考网址](https://www.cnblogs.com/bigsai/p/14099154.html)**
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
### HTTP方法
|
||||
|
||||
- **GET**
|
||||
|
||||
GET请求会向数据库发索取数据的请求,从而来获取资源,该请求就像数据库的select操作一样,**只是用来查询数据,不会影响资源的内容**。无论进行多少次操作,结果都是一样的
|
||||
|
||||
- **POST**
|
||||
|
||||
POST请求向服务器发送数据,但是该请求**会改变数据的内容(新添)**,就像数据库的`insert`操作一样,会创建新的内容,且POST请求的请求参数都是请求体中,其大小是没有限制的
|
||||
|
||||
- **PUT**
|
||||
|
||||
PUT请求是向服务器端发送数据的, 与POST请求不同的是,PUT请求**侧重于数据的修改 ,就像数据库中update一样**,而POST请求侧重于数据的增加
|
||||
|
||||
- **DELETE**
|
||||
|
||||
用来**删除资源**,和数据库中`delete`相对应
|
||||
|
||||
|
||||
|
||||
### 参数填写位置
|
||||
|
||||
- **Params(Query 参数)**:用于 GET 请求或其他将参数**附加在 URL 中**的情况。
|
||||
|
||||
- **Body(请求体)**:用于 POST、PUT 等请求方法,将参数**包含在请求体**中。
|
||||
|
||||
|
||||
|
||||
### 常见的请求文件类型及其适用场景
|
||||
|
||||
- **application/json**
|
||||
|
||||
用途:用于传输结构化数据,如对象和数组。
|
||||
|
||||
场景:客户端与服务器之间交换数据时,尤其是在前后端分离的应用中。
|
||||
|
||||
- **multipart/form-data**
|
||||
|
||||
用途:用于上传文件或包含文件的表单数据。
|
||||
|
||||
场景:用户上传图片、视频、文档等文件。
|
||||
|
||||
- **application/x-www-form-urlencoded**
|
||||
|
||||
用途:用于提交简单的表单数据。
|
||||
|
||||
场景:传统的表单提交,数据量较小且不包含文件。
|
||||
|
||||
- **application/octet-stream**
|
||||
|
||||
用途:用于传输二进制数据。
|
||||
|
||||
场景:下载文件或通过 API 提供文件流。
|
||||
92
note/资源/网络/认证.md
Normal file
92
note/资源/网络/认证.md
Normal file
@ -0,0 +1,92 @@
|
||||
## Cookie
|
||||
|
||||
| 维度 | 说明 |
|
||||
| :----------- | :----------------------------------------------------------- |
|
||||
| **本质** | 存储在浏览器端的一小段文本数据(通常 4KB 以内) |
|
||||
| **核心机制** | 浏览器在每次 HTTP 请求中**自动携带**符合域名/路径规则的 Cookie |
|
||||
| **关键属性** | `HttpOnly`(防 JS 读取)、`Secure`(仅 HTTPS)、`SameSite`(防 CSRF)、`Expires/Max-Age` |
|
||||
| **定位** | **传输载体,而非认证方案本身**——它负责把令牌(Session ID 或 Token)在客户端和服务器之间来回搬运 |
|
||||
|
||||
**优点**:
|
||||
|
||||
- 简单成熟,几乎所有 Web 框架默认集成
|
||||
- 服务端可随时销毁会话,控制力强
|
||||
- 敏感信息存在服务端,不暴露给客户端
|
||||
|
||||
**缺点**:
|
||||
|
||||
- 扩展性受限——多服务器需共享 Session(引入 Redis 等外部存储)
|
||||
- 依赖 Cookie,纯移动端/非浏览器环境不友好
|
||||
- 容易受到 CSRF 攻击(需额外防护)
|
||||
|
||||
## Session
|
||||
|
||||
| 维度 | 说明 |
|
||||
| :----------- | :----------------------------------------------------------- |
|
||||
| **本质** | 服务器端维护的用户会话数据(通常以 Map 结构存在内存、Redis 或数据库中) |
|
||||
| **认证流程** | 用户登录 → 服务器创建 Session → 将 Session ID 通过 `Set-Cookie` 返回 → 浏览器后续请求自动携带该 Cookie → 服务器通过 Session ID 查找会话数据验证身份 |
|
||||
| **核心特点** | **有状态**:服务器持有用户上下文,可随时主动吊销 |
|
||||
| **定位** | 经典的**服务端主导**的认证方式,适合传统 Web 应用和前后端未彻底分离的场景 |
|
||||
|
||||
**优点**:
|
||||
|
||||
- 简单成熟,几乎所有 Web 框架默认集成
|
||||
- 服务端可随时销毁会话,控制力强
|
||||
- 敏感信息存在服务端,不暴露给客户端
|
||||
|
||||
**缺点**:
|
||||
|
||||
- 扩展性受限——多服务器需共享 Session(引入 Redis 等外部存储)
|
||||
- 依赖 Cookie,纯移动端/非浏览器环境不友好
|
||||
- 容易受到 CSRF 攻击(需额外防护)
|
||||
|
||||
## JWT
|
||||
|
||||
| **本质** | 一段经过签名(或加密)的 JSON 数据,由 Header、Payload、Signature 三部分组成,以 Base64URL 编码 |
|
||||
| ------------ | ------------------------------------------------------------ |
|
||||
| **认证流程** | 用户登录 → 服务器验证凭据并签发 JWT → 客户端存储 Token → 后续请求在 `Authorization: Bearer <token>` 头中携带 → 服务器**仅验证签名和有效期**,无需查库 |
|
||||
| **核心特点** | **无状态**:Token 自身包含用户身份信息,服务器不需要维护会话 |
|
||||
| **定位** | 现代**前后端分离架构**和**多端(Web/iOS/Android)统一接入**的事实标准 |
|
||||
|
||||
**优点**:
|
||||
|
||||
- 天然无状态,服务端可随意水平扩展
|
||||
- 不依赖 Cookie,可用于移动端、小程序等非浏览器环境
|
||||
- 跨域友好(CORS 场景下比 Cookie 更灵活)
|
||||
- Payload 可携带少量业务数据,减少数据库查询
|
||||
|
||||
**缺点**:
|
||||
|
||||
- Token 一旦签发,在过期前无法主动撤销(需引入黑名单/版本号等机制)
|
||||
- Payload 仅 Base64 编码(非加密),敏感信息绝对不能放入
|
||||
- Token 体积比 Session ID 大,每次请求都传输有一定带宽开销
|
||||
|
||||
## SSO
|
||||
|
||||
| 维度 | 说明 |
|
||||
| :----------- | :----------------------------------------------------------- |
|
||||
| **本质** | 一种架构模式,通过**统一的认证中心(IdP)**,让用户在多个独立系统间共享登录状态 |
|
||||
| **认证流程** | 用户访问应用A → 重定向到 SSO 认证中心 → 登录并获取令牌 → 带回令牌访问应用A → 再访问应用B时,认证中心识别已登录状态,直接放行 |
|
||||
| **常见实现** | CAS、SAML、OAuth 2.0 + OpenID Connect |
|
||||
| **定位** | **企业级、多系统生态**的统一身份认证方案 |
|
||||
|
||||
**优点**:
|
||||
|
||||
- 用户体验极佳:一次登录,访问所有关联系统
|
||||
- 集中管理:统一账号体系、权限策略、安全审计
|
||||
- 安全性提升:减少密码泄露面,可配合多因素认证(MFA)
|
||||
|
||||
**缺点**:
|
||||
|
||||
- **单点故障风险**:认证中心一旦宕机,所有系统登录受影响
|
||||
- 实现复杂:涉及协议配置、令牌传递、跨域重定向等
|
||||
- 对认证中心的高可用要求极高
|
||||
|
||||
## OAuth 2.0
|
||||
|
||||
| 维度 | 说明 |
|
||||
| :----------- | :----------------------------------------------------------- |
|
||||
| **本质** | 一种**授权框架**(而非纯粹的认证协议),允许用户授权第三方应用在**不暴露自己密码**的情况下访问受保护资源 |
|
||||
| **核心角色** | 资源拥有者(用户)、客户端(第三方应用)、授权服务器、资源服务器 |
|
||||
| **核心流程** | 用户授权 → 第三方获取授权码 → 换取 Access Token → 持 Token 访问资源 |
|
||||
| **定位** | **第三方接入**和**开放平台**的标准授权方案(微信登录、Google 登录等) |
|
||||
17
note/随手记/Windows.md
Normal file
17
note/随手记/Windows.md
Normal file
@ -0,0 +1,17 @@
|
||||
## 快速复制文件路径
|
||||
|
||||
### Shift + 右键菜单(通用)
|
||||
|
||||
1. 在文件资源管理器中,**按住 `Shift` 键不放**
|
||||
2. 右键点击目标文件
|
||||
3. 选择 **「复制为路径(A)」**
|
||||
|
||||
### 功能区按钮
|
||||
|
||||
1. 选中文件
|
||||
2. 点击资源管理器顶部的 **「主页」** 选项卡
|
||||
3. 点击 **「复制路径」** 按钮(剪贴板图标)
|
||||
|
||||
### 拖拽到终端
|
||||
|
||||
- 直接把文件**拖入** PowerShell 或 CMD 窗口,会自动粘贴完整路径。
|
||||
50
note/随手记/go.md
Normal file
50
note/随手记/go.md
Normal file
@ -0,0 +1,50 @@
|
||||
## 句点引入
|
||||
|
||||
一个完整引入声明语句形式的引入名`importname`可以是一个句点(`.`)。 这样的引入称为句点引入。使用被句点引入的包中的导出代码要素时,限定标识符的前缀必须省略。
|
||||
|
||||
比如在下面这个例子中,`Println`和`Now`函数调用不需要带任何前缀。
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
. "fmt"
|
||||
. "time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
Println("Current time:", Now())
|
||||
}
|
||||
```
|
||||
|
||||
> 一般来说,句点引入不推荐使用,因为它们会导致较低的代码可读性
|
||||
|
||||
|
||||
|
||||
## map的坑
|
||||
|
||||
go的map内部是哈希表,元素会因 rehash(扩容)而移动到新的内存位置,如果允许 `&m[key]` 拿到一个指针,map 一旦扩容,这个指针就变成悬空指针(指向已失效的内存),为了避免这种内存安全问题,Go 直接禁止对 map 值取地址,下面是示例代码:
|
||||
```go
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func main() {
|
||||
m := map[int]User{1: {Name: "张三", Age: 20}}
|
||||
|
||||
// ❌ 编译错误:cannot assign to struct field m[1].Name in map
|
||||
m[1].Name = "李四"
|
||||
|
||||
// ✅ 正确的替代写法
|
||||
temp:=m[1]
|
||||
temp.Name = "李四"
|
||||
m[1]=temp
|
||||
}
|
||||
```
|
||||
|
||||
> **可寻址(addressable)**:能通过 `&` 拿到它内存地址的操作数。
|
||||
>
|
||||
> **不可寻址(not addressable)**:不能通过 `&` 拿到地址的操作数。
|
||||
|
||||
176
note/随手记/omos配置.md
Normal file
176
note/随手记/omos配置.md
Normal file
@ -0,0 +1,176 @@
|
||||
```json
|
||||
{
|
||||
"$schema": "https://unpkg.com/oh-my-opencode-slim@latest/oh-my-opencode-slim.schema.json",
|
||||
"preset": "zhipu",
|
||||
"presets": {
|
||||
"opencode-go": {
|
||||
"orchestrator": {
|
||||
"model": "opencode-go/glm-5.2",
|
||||
"skills": [
|
||||
"*"
|
||||
],
|
||||
"mcps": [
|
||||
"*",
|
||||
"!context7"
|
||||
]
|
||||
},
|
||||
"oracle": {
|
||||
"model": "deepseek/deepseek-v4-pro",
|
||||
"variant": "max",
|
||||
"skills": [
|
||||
"simplify"
|
||||
],
|
||||
"mcps": []
|
||||
},
|
||||
"council": {
|
||||
"model": "opencode-go/qwen3.7-max",
|
||||
"variant": "high",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"librarian": {
|
||||
"model": "opencode-go/minimax-m3",
|
||||
"skills": [],
|
||||
"mcps": [
|
||||
"websearch",
|
||||
"context7",
|
||||
"gh_grep"
|
||||
]
|
||||
},
|
||||
"explorer": {
|
||||
"model": "opencode-go/mimo-v2.5-pro",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"designer": {
|
||||
"model": "opencode-go/kimi-k2.7-code",
|
||||
"variant": "medium",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"fixer": {
|
||||
"model": "opencode-go/deepseek-v4-flash",
|
||||
"variant": "high",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"observer": {
|
||||
"model": "opencode-go/kimi-k2.7-code",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
}
|
||||
},
|
||||
"zhipu": {
|
||||
"orchestrator": {
|
||||
"model": "zhipuai-coding-plan/glm-5.2",
|
||||
"skills": [
|
||||
"*"
|
||||
],
|
||||
"mcps": [
|
||||
"*",
|
||||
"!context7"
|
||||
]
|
||||
},
|
||||
"oracle": {
|
||||
"model": "zhipuai-coding-plan/glm-5.2",
|
||||
"variant": "max",
|
||||
"skills": [
|
||||
"simplify"
|
||||
],
|
||||
"mcps": []
|
||||
},
|
||||
"council": {
|
||||
"model": "zhipuai-coding-plan/glm-5.1",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"librarian": {
|
||||
"model": "zhipuai-coding-plan/glm-5-turbo",
|
||||
"skills": [],
|
||||
"mcps": [
|
||||
"websearch",
|
||||
"context7",
|
||||
"gh_grep"
|
||||
]
|
||||
},
|
||||
"explorer": {
|
||||
"model": "zhipuai-coding-plan/glm-5-turbo",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"designer": {
|
||||
"model": "zhipuai-coding-plan/glm-5.2",
|
||||
"variant": "medium",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"fixer": {
|
||||
"model": "zhipuai-coding-plan/glm-5.2",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"observer": {
|
||||
"model": "zhipuai-coding-plan/glm-4.6v",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
}
|
||||
},
|
||||
"deepseek": {
|
||||
"orchestrator": {
|
||||
"model": "deepseek/deepseek-v4-pro",
|
||||
"variant": "high",
|
||||
"skills": [
|
||||
"*"
|
||||
],
|
||||
"mcps": [
|
||||
"*",
|
||||
"!context7"
|
||||
]
|
||||
},
|
||||
"oracle": {
|
||||
"model": "deepseek/deepseek-v4-pro",
|
||||
"variant": "max",
|
||||
"skills": [
|
||||
"simplify"
|
||||
],
|
||||
"mcps": []
|
||||
},
|
||||
"council": {
|
||||
"model": "deepseek/deepseek-v4-pro",
|
||||
"variant": "medium",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"librarian": {
|
||||
"model": "deepseek/deepseek-v4-flash",
|
||||
"skills": [],
|
||||
"mcps": [
|
||||
"websearch",
|
||||
"context7",
|
||||
"gh_grep"
|
||||
]
|
||||
},
|
||||
"explorer": {
|
||||
"model": "deepseek/deepseek-v4-flash",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"designer": {
|
||||
"model": "deepseek/deepseek-v4-pro",
|
||||
"variant": "medium",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
},
|
||||
"fixer": {
|
||||
"model": "deepseek/deepseek-v4-flash",
|
||||
"variant": "high",
|
||||
"skills": [],
|
||||
"mcps": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"disabled_agents": []
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
56
note/随手记/算法.md
Normal file
56
note/随手记/算法.md
Normal file
@ -0,0 +1,56 @@
|
||||
## 轮询算法
|
||||
|
||||
### 平滑加权轮询
|
||||
|
||||
#### 原理
|
||||
|
||||
每台服务器维护一个 `当前权重`(currentWeight),每次选择 `currentWeight` 最大的服务器,选中后将其 `currentWeight` 减去总权重,然后**所有服务器都加上自己的固定权重**。如此循环,高权重节点被选中的频率更高,但不会连续出现。
|
||||
|
||||
#### 实际应用
|
||||
|
||||
- **Nginx** 的 `upstream` 默认负载均衡算法
|
||||
- **LVS**(Linux Virtual Server)
|
||||
- 几乎所有需要「按比例分配且平滑」的场景
|
||||
|
||||
#### 轮询示例
|
||||
|
||||
```go
|
||||
type server struct {
|
||||
name string
|
||||
weight int
|
||||
curWeight int
|
||||
}
|
||||
|
||||
func NextServer(servers []*server) *server {
|
||||
var totalWeight int
|
||||
// 1.先给所有服务器加上各自的固定权重
|
||||
for i := range servers {
|
||||
servers[i].curWeight += servers[i].weight
|
||||
totalWeight += servers[i].weight
|
||||
}
|
||||
// 2.再找出 curWeight 最大的服务器
|
||||
maxIdx := 0
|
||||
for i := 1; i < len(servers); i++ {
|
||||
if servers[i].curWeight > servers[maxIdx].curWeight {
|
||||
maxIdx = i
|
||||
}
|
||||
}
|
||||
// 3.选中的服务器减去总权重
|
||||
servers[maxIdx].curWeight -= totalWeight
|
||||
return servers[maxIdx]
|
||||
}
|
||||
```
|
||||
|
||||
| 轮次 | 操作前 (currentWeight) | 选中 | 操作后 |
|
||||
| ---- | ---------------------- | ----- | --------------- |
|
||||
| 初始 | A=0, B=0, C=0 | — | — |
|
||||
| 1 | A=5, B=1, C=1 | **A** | A=−2, B=1, C=1 |
|
||||
| 2 | A=3, B=2, C=2 | **A** | A=−4, B=2, C=2 |
|
||||
| 3 | A=1, B=3, C=3 | **B** | A=1, B=−4, C=3 |
|
||||
| 4 | A=6, B=−3, C=4 | **A** | A=−1, B=−3, C=4 |
|
||||
| 5 | A=4, B=−2, C=5 | **C** | A=4, B=−2, C=−2 |
|
||||
| 6 | A=9, B=−1, C=−1 | **A** | A=2, B=−1, C=−1 |
|
||||
| 7 | A=7, B=0, C=0 | **A** | A=0, B=0, C=0 |
|
||||
|
||||
|
||||
|
||||
4
note/随手记/网址.md
Normal file
4
note/随手记/网址.md
Normal file
@ -0,0 +1,4 @@
|
||||
[Typora onelight 主题](https://github.com/caolib/typora-onelight-theme?tab=readme-ov-file#4%E5%85%B3%E4%BA%8E%E5%AD%97%E4%BD%93)
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user