Compare commits
No commits in common. "a2dbd51f3519829a29606a128697e1638d3c142d" and "f7f5d379a90e724e34b70c0755afa11c844bcf25" have entirely different histories.
a2dbd51f35
...
f7f5d379a9
1
.gitignore
vendored
1
.gitignore
vendored
@ -30,4 +30,5 @@ build/
|
|||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
# ---- Note 目录 ----
|
# ---- Note 目录 ----
|
||||||
|
note/assets/
|
||||||
note/项目/
|
note/项目/
|
||||||
36
AGENTS.md
36
AGENTS.md
@ -1,36 +0,0 @@
|
|||||||
# AGENTS.md
|
|
||||||
|
|
||||||
## 仓库结构
|
|
||||||
|
|
||||||
按语言分层的个人练习仓库,每种语言一个顶层目录,各自独立管理依赖。
|
|
||||||
|
|
||||||
| 目录 | 说明 |
|
|
||||||
|---|---|
|
|
||||||
| `go/` | Go module `lab`(Go 1.26.2),go.mod 在该目录内 |
|
|
||||||
| `note/` | 个人笔记(非代码),`note/项目/` 被 gitignore |
|
|
||||||
| `dart/` | 预留,尚未建立 |
|
|
||||||
|
|
||||||
## Go 约定
|
|
||||||
|
|
||||||
- **Module 在 `go/` 目录下,不在仓库根**——所有 go 命令需在 `go/` 内执行
|
|
||||||
- 每个叶子目录 = 一个独立小程序(`package main` + `main.go`)
|
|
||||||
- 多个小程序可并存,不同目录、各自独立
|
|
||||||
- 主题目录(basics/concurrency/stdlib/patterns/algorithms/web/testing/project)可随时增删
|
|
||||||
- 测试文件用 `*_test.go`,运行单个测试:`cd go && go test ./testing/ -run TestSliceAppend`
|
|
||||||
|
|
||||||
## 开发命令
|
|
||||||
|
|
||||||
```
|
|
||||||
# Go——所有命令在 go/ 目录下执行
|
|
||||||
cd go
|
|
||||||
go run ./<主题>/<程序名>/ # 运行单个程序
|
|
||||||
go test ./... # 运行全部测试
|
|
||||||
go test ./testing/ -v # 运行 testing 包测试
|
|
||||||
go mod tidy # 整理依赖
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
- 仓库无 CI、无 pre-commit hooks、无代码检查——每个程序自行保证可编译即可
|
|
||||||
- 笔记和练习代码严格分离:程序相关说明写在程序目录的 README.md,系统性知识放 `note/`
|
|
||||||
- `.gitignore` 已覆盖 Go 二进制、Dart/Flutter 构建产物、IDE 配置、操作系统文件
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
type User struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUser() *User {
|
|
||||||
u := User{}
|
|
||||||
return &u
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClosureFunc() func() int {
|
|
||||||
a := 1
|
|
||||||
return func() int {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func main() {
|
|
||||||
fmt.Println(NewUser())
|
|
||||||
cf:= ClosureFunc()
|
|
||||||
fmt.Println(cf())
|
|
||||||
}
|
|
||||||
12
go/go.mod
12
go/go.mod
@ -1,15 +1,3 @@
|
|||||||
module lab
|
module lab
|
||||||
|
|
||||||
go 1.26.2
|
go 1.26.2
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/richardlehane/mscfb v1.0.7 // indirect
|
|
||||||
github.com/richardlehane/msoleps v1.0.6 // indirect
|
|
||||||
github.com/tiendc/go-deepcopy v1.7.2 // indirect
|
|
||||||
github.com/xuri/efp v0.0.1 // indirect
|
|
||||||
github.com/xuri/excelize/v2 v2.11.0 // indirect
|
|
||||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
|
|
||||||
golang.org/x/crypto v0.53.0 // indirect
|
|
||||||
golang.org/x/net v0.56.0 // indirect
|
|
||||||
golang.org/x/text v0.38.0 // indirect
|
|
||||||
)
|
|
||||||
|
|||||||
18
go/go.sum
18
go/go.sum
@ -1,18 +0,0 @@
|
|||||||
github.com/richardlehane/mscfb v1.0.7 h1:oeoiM0WE79vHwE8RpIYYvIAc8ajTH2mb6UZm55/+EB0=
|
|
||||||
github.com/richardlehane/mscfb v1.0.7/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
|
|
||||||
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
|
|
||||||
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
|
||||||
github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=
|
|
||||||
github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
|
|
||||||
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
|
|
||||||
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
|
||||||
github.com/xuri/excelize/v2 v2.11.0 h1:HxaEFl6sRN2+8J5a8HaKq+0M4FsjBGMnWWtjOCPSG88=
|
|
||||||
github.com/xuri/excelize/v2 v2.11.0/go.mod h1:jxFLbzaIwGQ5ufFNvYfUOHqXhfPaNmP14KWfmNz2Uak=
|
|
||||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
|
|
||||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
|
||||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
|
||||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
|
||||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
|
||||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
|
||||||
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
|
||||||
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package regularmatch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestChineseRegExp(t *testing.T) {
|
|
||||||
reg, err := regexp.Compile("[\u4e00-\u9fa5]")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to compile regex: %v", err)
|
|
||||||
}
|
|
||||||
matchStrSlice := reg.FindAllString("hello 世界", -1)
|
|
||||||
|
|
||||||
if len(matchStrSlice) != 2 {
|
|
||||||
t.Errorf("Expected 2 matches, got %d", len(matchStrSlice))
|
|
||||||
}
|
|
||||||
if matchStrSlice[0] != "世" || matchStrSlice[1] != "界" {
|
|
||||||
t.Errorf("Expected [世, 界], got %v", matchStrSlice)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func appendSlice(s []int, n int) {
|
|
||||||
s = append(s, n)
|
|
||||||
fmt.Printf("len=%d,cap=%d\n", len(s), cap(s))
|
|
||||||
}
|
|
||||||
func TestSliceAppend(t *testing.T) {
|
|
||||||
s1 := make([]int, 5)
|
|
||||||
appendSlice(s1, 10)
|
|
||||||
if len(s1) != 5 || cap(s1) != 5 {
|
|
||||||
t.Errorf("Expected len=5, cap=5; got len=%d, cap=%d", len(s1), cap(s1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB |
@ -35,12 +35,11 @@
|
|||||||
|
|
||||||
#### 四、合并与变基
|
#### 四、合并与变基
|
||||||
|
|
||||||
| 操作 | 命令 | 说明 |
|
| 操作 | 命令 | 说明 |
|
||||||
| -------------- | ------------------------------------ | ------------------------------- |
|
| -------------- | ------------------------------------ | ------------------------- |
|
||||||
| 合并分支 | `git merge feature/xxx` | 把目标分支合并进当前分支 |
|
| 合并分支 | `git merge feature/xxx` | 把目标分支合并进当前分支 |
|
||||||
| 取消合并 | `git merge --abort` | 终止合并,直接回退到合并前的状态 |
|
| 变基(rebase) | `git rebase dev` | 让你的提交在最新 `dev` 上 |
|
||||||
| 变基(rebase) | `git rebase dev` | 让你的提交在最新 `dev` 上 |
|
| 解决冲突后继续 | `git add . && git rebase --continue` | 继续变基或合并流程 |
|
||||||
| 解决冲突后继续 | `git add . && git rebase --continue` | 继续变基或合并流程 |
|
|
||||||
|
|
||||||
#### 五、查看状态和差异
|
#### 五、查看状态和差异
|
||||||
|
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
## Nginx 反代未透传客户端 IP 导致服务端日志全量变为 127.0.0.1
|
|
||||||
|
|
||||||
### 现象
|
|
||||||
|
|
||||||
后端解析IP后全量变成 `127.0.0.1`。
|
|
||||||
|
|
||||||
### 原因
|
|
||||||
|
|
||||||
后端解析IP的顺序是
|
|
||||||
```
|
|
||||||
X-Forwarded-For → X-Real-IP → RemoteAddr
|
|
||||||
```
|
|
||||||
|
|
||||||
**Nginx**转发至后端服务的 location 块缺少`proxy_set_header`指令:
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
location /olive3 {
|
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:55430;
|
|
||||||
|
|
||||||
proxy_connect_timeout 300s;
|
|
||||||
|
|
||||||
proxy_send_timeout 300s;
|
|
||||||
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
|
|
||||||
在缺失的 location 块中补充 header 透传:
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
location /api {
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_pass http://127.0.0.1:55430;
|
|
||||||
# ... 其他配置不变
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- `$proxy_add_x_forwarded_for`:将客户端真实 IP 追加到已有 `X-Forwarded-For` 尾部,而非覆盖
|
|
||||||
- `$remote_addr`:Nginx 直接看到的对端地址,作为 `X-Real-IP` 传递
|
|
||||||
|
|
||||||
@ -210,54 +210,3 @@ func TestJson(t *testing.T) {
|
|||||||
1. **小请求(配置、JSON)**:使用 `io.ReadAll` 存入内存,再通过 `io.NopCloser` 塞回 `r.Body` 或设置 `r.GetBody`。
|
1. **小请求(配置、JSON)**:使用 `io.ReadAll` 存入内存,再通过 `io.NopCloser` 塞回 `r.Body` 或设置 `r.GetBody`。
|
||||||
2. **中等请求(签名校验)**:使用 `io.TeeReader` 边读边处理,节省一次全量扫描。
|
2. **中等请求(签名校验)**:使用 `io.TeeReader` 边读边处理,节省一次全量扫描。
|
||||||
3. **大请求(文件上传)**:**禁止 ReadAll**。直接流式 `io.Copy` 到目的地,或使用临时文件做中转。
|
3. **大请求(文件上传)**:**禁止 ReadAll**。直接流式 `io.Copy` 到目的地,或使用临时文件做中转。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 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)**:不能通过 `&` 拿到地址的操作数。
|
|
||||||
|
|
||||||
## 句点引入
|
|
||||||
|
|
||||||
一个完整引入声明语句形式的引入名`importname`可以是一个句点(`.`)。 这样的引入称为句点引入。使用被句点引入的包中的导出代码要素时,限定标识符的前缀必须省略。
|
|
||||||
|
|
||||||
比如在下面这个例子中,`Println`和`Now`函数调用不需要带任何前缀。
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "fmt"
|
|
||||||
. "time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
Println("Current time:", Now())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> 一般来说,句点引入不推荐使用,因为它们会导致较低的代码可读性
|
|
||||||
|
|
||||||
|
|||||||
@ -1,73 +0,0 @@
|
|||||||
Go 1.24 起,`map` 的底层实现从传统的 `hmap` + `bmap` 哈希表,彻底切换到了 Swiss Table(瑞士表)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Group内存布局图
|
|
||||||
|
|
||||||
你可以直接复制以下文本块到你的 Markdown 笔记中(使用 text 包裹):
|
|
||||||
|
|
||||||
codeText
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
+-------------------------------------------------------------------------------+
|
|
||||||
| 单 Group 内存布局 |
|
|
||||||
+--------------------------+----------------------------+-----------------------+
|
|
||||||
| 1. Metadata 控制字节区 | 2. 连续 Key 存储区 | 3. 连续 Value 存储区 |
|
|
||||||
+--------------------------+----------------------------+-----------------------+
|
|
||||||
| [M0][M1][M2]...[M7] | [K0][K1][K2]...[K7] | [V0][V1][V2]...[V7] |
|
|
||||||
+--------------------------+----------------------------+-----------------------+
|
|
||||||
| <- 固定 8 个字节 -> | <- 长度取决于 Key 类型 -> | <- 长度取决于 Val -> |
|
|
||||||
| <- 一次性载入寄存器对比 -> | |
|
|
||||||
```
|
|
||||||
|
|
||||||
**为什么这样设计?(设计优势):**
|
|
||||||
|
|
||||||
1.
|
|
||||||
2. **避免内存对齐填充(Padding)**:如果采用 [Meta][Key][Value] 交叉排列,由于不同类型的 Key/Value 字节大小不同,为了对齐,Go 必须在它们之间插入大量空白填充字节,浪费空间。分块连续存储消除了组内的对齐损耗。
|
|
||||||
3. **对 CPU 缓存友好**:8 字节的 Metadata 紧密相连,一次 Cache Line 填充就能把整组的控制信息全部读入,极大地提高了缓存命中率。
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 读取流程
|
|
||||||
|
|
||||||
以下为您整理的完整、正确的读取逻辑,您可以直接复制使用:
|
|
||||||
|
|
||||||
#### 1.哈希计算与分段 (Hash Splitting)
|
|
||||||
|
|
||||||
- 将 Key 传入哈希函数,计算出一个 **64 位的哈希值**。
|
|
||||||
- 该哈希值被拆分为两部分:**H1(高 57 位)**:用于定位哈希表中的初始 Group 索引。**H2(低 7 位)**:作为特征值(指纹),存储在 Group 的 Metadata 中,用于快速匹配。
|
|
||||||
|
|
||||||
#### 2.定位初始 Group (Locate Group)
|
|
||||||
|
|
||||||
- 计算初始 Group 索引:group_index = H1 & (Group数量 - 1)。
|
|
||||||
|
|
||||||
> 可以理解与$2^B$进行取模运算,但是**位与运算**效率更高且等价。
|
|
||||||
|
|
||||||
#### 3.组内快速匹配 (Group-level SWAR Match)
|
|
||||||
|
|
||||||
- **一次性加载**:将目标 Group 的 8 字节 Metadata 一次性载入一个 64 位寄存器中。
|
|
||||||
- **并行对比(SWAR 技术)**:利用位运算,将 7 位的 H2 同时与这 8 个 Metadata 字节进行并行对比,输出一个 8 位的位掩码(Bitmask)。位掩码中为 1 的位,代表该位置的 H2 与目标 H2 匹配成功。这一步极快,完全避免了循环遍历。
|
|
||||||
|
|
||||||
#### 4.冲突解决与探测循环 (Verification & Probing Loop)
|
|
||||||
|
|
||||||
根据位掩码的匹配结果,执行以下逻辑:
|
|
||||||
|
|
||||||
1. 依次根据匹配成功的索引,去 **Key 存储区** 找到对应的真实 Key。
|
|
||||||
2. 进行完整的 Key 等值对比(如 if key == targetKey):**若匹配成功**:直接去 **Value 存储区** 对应偏移量取出 Value 并返回。**若匹配失败**:说明发生了 **H2 哈希冲突**(即不同的 Key 产生了相同的 H2),继续对比下一个匹配的槽位。
|
|
||||||
3. 如果当前 Group 中所有匹配了 H2 的槽位都对比完了,仍未找到匹配的 Key,则**跳转至【情况 B】**。
|
|
||||||
|
|
||||||
此时需要检查当前 Group 的 Metadata 状态,决定是继续向后寻找还是停止:
|
|
||||||
|
|
||||||
- **若当前 Group 中存在“空位”(Empty,0xFF)**:
|
|
||||||
|
|
||||||
说明探测链在此处断开,该 Key 在 Map 中**一定不存在**,直接返回 nil 或零值。
|
|
||||||
|
|
||||||
- **若当前 Group 中无空位,但存在“墓碑”(Tombstone,0x80)或已满**:
|
|
||||||
|
|
||||||
虽然当前 Group 没找到,但可能因为历史删除操作(留下了墓碑)或哈希冲突,导致数据被存到了后续的 Group。不能停止!使用**二次探测算法(Quadratic Probing)**计算下一个 Group 的索引,跳转回 **【3.组内快速匹配】** 继续循环寻找。
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
## 命名规则
|
|
||||||
|
|
||||||
> [《布尔变量起名的艺术》](https://thatamazingprogrammer.com/posts/stop-naming-your-variables-flag-the-art-of-boolean-prefixes/)
|
|
||||||
|
|
||||||
### 使用正确的前缀
|
|
||||||
|
|
||||||
(1)**is**:描述事物的状态,后面跟形容词,比如 isActive,isDeleted,isEmpty。
|
|
||||||
|
|
||||||
(2)**has**:描述事物的所有权或包含关系,后面跟名词,比如 hasAccess,hasChildren,hasValidationErrors。
|
|
||||||
|
|
||||||
(3)**can**:描述事物的能力或权限,比如 canEdit,canDelete,canRetry。
|
|
||||||
|
|
||||||
(4)**should**:描述事物的意图或逻辑,比如 shouldRetry,shouldCacheResponse。
|
|
||||||
|
|
||||||
### 其他
|
|
||||||
|
|
||||||
永远不在布尔变量名中使用否定词,比如isDisabled,因为当使用在if语句中会让大脑进行双重否定运算
|
|
||||||
@ -14,5 +14,4 @@
|
|||||||
|
|
||||||
### 拖拽到终端
|
### 拖拽到终端
|
||||||
|
|
||||||
- 直接把文件**拖入** PowerShell 或 CMD 窗口,会自动粘贴完整路径。
|
- 直接把文件**拖入** 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)**:不能通过 `&` 拿到地址的操作数。
|
||||||
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
## excelize库
|
|
||||||
|
|
||||||
读写Excel的Go库
|
|
||||||
|
|
||||||
[github](https://github.com/qax-os/excelize)
|
|
||||||
|
|
||||||
## 基本用法
|
|
||||||
|
|
||||||
### 创建工作簿
|
|
||||||
|
|
||||||
```go
|
|
||||||
f := excelize.NewFile()
|
|
||||||
defer func() {
|
|
||||||
if err := f.Close(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
// 创建一个新的Sheet,返回的index为该工作簿的索引
|
|
||||||
index, err := f.NewSheet("SheetName")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("创建Sheet失败: %w", err)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 打开文件
|
|
||||||
|
|
||||||
```go
|
|
||||||
f, err := excelize.OpenFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("打开 Excel失败: %w", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err := f.Close(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
```
|
|
||||||
|
|
||||||
### 写入cell值
|
|
||||||
|
|
||||||
```go
|
|
||||||
f.SetCellValue("SheetName", "B2", 100)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 设置工作簿默认活动工作表
|
|
||||||
|
|
||||||
```go
|
|
||||||
f.SetActiveSheet(index)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 创建或更新excel表
|
|
||||||
|
|
||||||
```go
|
|
||||||
if err := f.SaveAs("Book1.xlsx"); err != nil {
|
|
||||||
return fmt.Errorf("保存失败: %w", err)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 获取指定cell值
|
|
||||||
|
|
||||||
```go
|
|
||||||
cell, err := f.GetCellValue("Sheet1", "B2")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("读取cell失败: %w", err)
|
|
||||||
}
|
|
||||||
fmt.Println(cell)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 获取所有工作簿的cell值(二维数组)
|
|
||||||
|
|
||||||
```go
|
|
||||||
rows, err := f.GetRows("Sheet1")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("读取失败: %w", err)
|
|
||||||
}
|
|
||||||
for _, row := range rows {
|
|
||||||
for _, colCell := range row {
|
|
||||||
fmt.Print(colCell, "\t")
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
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": []
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
@ -1,476 +0,0 @@
|
|||||||
> 感觉还是不如typora好使啊,以后买个正版吧
|
|
||||||
|
|
||||||
```css
|
|
||||||
/**
|
|
||||||
* MarkText One Light Dark 主题 (仿 Typora onelight-dark:https://github.com/caolib/typora-onelight-theme)
|
|
||||||
*
|
|
||||||
* 使用方法:
|
|
||||||
* 在 MarkText 中打开 设置 → 主题 → 自定义 CSS,
|
|
||||||
* 将本文件全部内容粘贴进去,保存即可。
|
|
||||||
*
|
|
||||||
* 配色来源: Typora onelight-dark theme by caolib
|
|
||||||
* 兼容: MarkText v0.19.x (旧引擎) / v0.20+ (新引擎)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* CSS 变量 — 使用 camelCase 命名 (旧引擎 v0.19.x 兼容)
|
|
||||||
* ==================================================================== */
|
|
||||||
:root {
|
|
||||||
/* —— 编辑器核心 —— */
|
|
||||||
--themeColor: #5c99f3;
|
|
||||||
--themeColor90: rgba(92, 153, 243, 0.9);
|
|
||||||
--themeColor80: rgba(92, 153, 243, 0.8);
|
|
||||||
--themeColor70: rgba(92, 153, 243, 0.7);
|
|
||||||
--themeColor60: rgba(92, 153, 243, 0.6);
|
|
||||||
--themeColor50: rgba(92, 153, 243, 0.5);
|
|
||||||
--themeColor40: rgba(92, 153, 243, 0.4);
|
|
||||||
--themeColor30: rgba(92, 153, 243, 0.3);
|
|
||||||
--themeColor20: rgba(92, 153, 243, 0.2);
|
|
||||||
--themeColor10: rgba(92, 153, 243, 0.1);
|
|
||||||
--highlightThemeColor: #e94ab9;
|
|
||||||
|
|
||||||
--highlightColor: #ffffff10;
|
|
||||||
--selectionColor: #3266d0;
|
|
||||||
--editorColor: #c3c3c3;
|
|
||||||
--editorColor80: #c3c3c3;
|
|
||||||
--editorColor60: rgba(195, 195, 195, 0.6);
|
|
||||||
--editorColor50: rgba(195, 195, 195, 0.5);
|
|
||||||
--editorColor40: rgba(195, 195, 195, 0.4);
|
|
||||||
--editorColor30: rgba(195, 195, 195, 0.3);
|
|
||||||
--editorColor10: rgba(195, 195, 195, 0.1);
|
|
||||||
--editorColor04: rgba(195, 195, 195, 0.04);
|
|
||||||
--editorBgColor: #1f1f1e;
|
|
||||||
--editorAreaWidth: 900px;
|
|
||||||
--deleteColor: #ff6b6b;
|
|
||||||
--iconColor: rgba(195, 195, 195, 0.56);
|
|
||||||
--codeBgColor: #282c34;
|
|
||||||
--codeBlockBgColor: #282c34;
|
|
||||||
--footnoteBgColor: rgba(51, 51, 51, 0.5);
|
|
||||||
--inputBgColor: #3d404e;
|
|
||||||
--focusColor: #5c99f3;
|
|
||||||
|
|
||||||
/* —— 按钮 —— */
|
|
||||||
--buttonFontColor: #c3c3c3;
|
|
||||||
--buttonBgColor: #333333;
|
|
||||||
--buttonBorder: 1px solid #353a45;
|
|
||||||
--buttonShadow: none;
|
|
||||||
--buttonFontColorHover: #ffffff;
|
|
||||||
--buttonBgColorHover: #414855;
|
|
||||||
--buttonBorderHover: var(--buttonBorder);
|
|
||||||
--buttonFontColorActive: var(--buttonFontColor);
|
|
||||||
--buttonBgColorActive: #2a2d35;
|
|
||||||
--buttonBorderActive: var(--buttonBorder);
|
|
||||||
--buttonFocusBorder: 1px solid #5c99f3;
|
|
||||||
--buttonFocusShadow: 0 0 0 1px rgba(92, 153, 243, 0.3);
|
|
||||||
|
|
||||||
--buttonPrimaryFontColor: #ffffff;
|
|
||||||
--buttonPrimaryBgColor: #5c99f3;
|
|
||||||
--buttonPrimaryBorder: 1px solid #4a8ad9;
|
|
||||||
--buttonPrimaryShadow: none;
|
|
||||||
--buttonPrimaryFontColorHover: var(--buttonPrimaryFontColor);
|
|
||||||
--buttonPrimaryBgColorHover: #4a8ad9;
|
|
||||||
--buttonPrimaryBorderHover: var(--buttonPrimaryBorder);
|
|
||||||
--buttonPrimaryFontColorActive: var(--buttonPrimaryFontColor);
|
|
||||||
--buttonPrimaryBgColorActive: #3d7bc4;
|
|
||||||
--buttonPrimaryBorderActive: var(--buttonPrimaryBorder);
|
|
||||||
--buttonPrimaryFocusBorder: none;
|
|
||||||
--buttonPrimaryFocusShadow: inset 0 0 0 1px rgba(24, 26, 31, 0.5), 0 0 0 1px #5c99f3;
|
|
||||||
|
|
||||||
/* —— Markdown 元素 —— */
|
|
||||||
--headingColor: #c3c3c3;
|
|
||||||
--h1Color: #c3c3c3;
|
|
||||||
--h2Color: #c3c3c3;
|
|
||||||
--h3Color: #c3c3c3;
|
|
||||||
--h4Color: #ffffff;
|
|
||||||
--h5Color: #c3c3c3;
|
|
||||||
--h6Color: #c3c3c3;
|
|
||||||
--blockquoteTextColor: rgba(195, 195, 195, 0.8);
|
|
||||||
--blockquoteBorderColor: #5c99f3;
|
|
||||||
--hrColor: #5c99f3;
|
|
||||||
--linkColor: #e94ab9;
|
|
||||||
--strongColor: #5c99f3;
|
|
||||||
--emColor: #e94ab9;
|
|
||||||
--listMarkerColor: #5c99f3;
|
|
||||||
--tableBorderColor: #393e49;
|
|
||||||
|
|
||||||
/* —— 侧边栏 —— */
|
|
||||||
--sideBarColor: #c3c3c3;
|
|
||||||
--sideBarIconColor: var(--iconColor);
|
|
||||||
--sideBarTitleColor: #c3c3c3;
|
|
||||||
--sideBarTextColor: #7a7a7a;
|
|
||||||
--sideBarBgColor: #1f1f1e;
|
|
||||||
--sideBarItemHoverBgColor: #333333;
|
|
||||||
--itemBgColor: #333333;
|
|
||||||
|
|
||||||
/* —— 浮动层 —— */
|
|
||||||
--floatFontColor: #c3c3c3;
|
|
||||||
--floatBgColor: #353a45;
|
|
||||||
--floatHoverColor: #414855;
|
|
||||||
--floatBorderColor: #353a45;
|
|
||||||
--floatShadow: rgba(0, 0, 0, 0.3);
|
|
||||||
--maskColor: rgba(0, 0, 0, 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 全局背景 — 统一为 Typora onelight-dark 底色 #1f1f1e
|
|
||||||
* ==================================================================== */
|
|
||||||
html, body {
|
|
||||||
background-color: #1f1f1e;
|
|
||||||
}
|
|
||||||
.editor-wrapper {
|
|
||||||
background-color: #1f1f1e;
|
|
||||||
}
|
|
||||||
.editor-component {
|
|
||||||
background-color: #1f1f1e;
|
|
||||||
}
|
|
||||||
#ag-editor-id {
|
|
||||||
background-color: #1f1f1e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 滚动条
|
|
||||||
* ==================================================================== */
|
|
||||||
::-webkit-scrollbar,
|
|
||||||
::-webkit-scrollbar-corner {
|
|
||||||
background: var(--editorBgColor);
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar:vertical { width: 8px; }
|
|
||||||
::-webkit-scrollbar:vertical:hover { width: 10px; }
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: rgba(134, 134, 134, 0.27);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 弹窗 (Element UI)
|
|
||||||
* ==================================================================== */
|
|
||||||
.v-modal { background: #08090a !important; opacity: 0.65 !important; }
|
|
||||||
.el-dialog,
|
|
||||||
.el-dialog.ag-dialog-table {
|
|
||||||
border-radius: 6px !important;
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !important;
|
|
||||||
border: 1px solid #353a45 !important;
|
|
||||||
background: #2a2a29 !important;
|
|
||||||
}
|
|
||||||
.el-button:focus { color: var(--buttonFontColor); }
|
|
||||||
.el-button--primary:focus {
|
|
||||||
color: var(--buttonPrimaryFontColor);
|
|
||||||
background: var(--buttonPrimaryBgColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 标题栏 / 浮动菜单
|
|
||||||
* ==================================================================== */
|
|
||||||
.title-bar .frameless-titlebar-button > div > svg { fill: #c3c3c3; }
|
|
||||||
.title-bar .frameless-titlebar-minimize:hover,
|
|
||||||
.title-bar .frameless-titlebar-toggle:hover {
|
|
||||||
background-color: rgba(195, 195, 195, 0.05) !important;
|
|
||||||
}
|
|
||||||
.input-wrapper {
|
|
||||||
border-radius: 5px !important;
|
|
||||||
border: 1px solid #353a45 !important;
|
|
||||||
background: #2a2a29 !important;
|
|
||||||
}
|
|
||||||
.ag-front-menu,
|
|
||||||
.ag-float-wrapper {
|
|
||||||
box-shadow: 0 4px 8px 0 var(--floatShadow) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 侧边栏
|
|
||||||
* ==================================================================== */
|
|
||||||
.side-bar { border-right: 1px solid #333333 !important; }
|
|
||||||
.left-column ul > li > svg { fill: rgba(195, 195, 195, 0.6) !important; }
|
|
||||||
.left-column ul > li:hover > svg { fill: #ffffff !important; }
|
|
||||||
.left-column ul > li.active > svg { fill: #5c99f3 !important; }
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 标签栏
|
|
||||||
* ==================================================================== */
|
|
||||||
.editor-tabs {
|
|
||||||
box-shadow: none !important;
|
|
||||||
background: var(--editorBgColor) !important;
|
|
||||||
}
|
|
||||||
.editor-tabs:after {
|
|
||||||
position: absolute;
|
|
||||||
content: '';
|
|
||||||
border-bottom: 1px solid #333333;
|
|
||||||
bottom: 0; left: 0; right: 0; z-index: 1;
|
|
||||||
}
|
|
||||||
.editor-tabs ul.tabs-container:after {
|
|
||||||
position: absolute;
|
|
||||||
content: '';
|
|
||||||
border-bottom: 1px solid #333333;
|
|
||||||
bottom: 0; left: 0; right: 0; z-index: 2;
|
|
||||||
}
|
|
||||||
.tabs-container > li,
|
|
||||||
.tabs-container > li.active { background: var(--editorBgColor) !important; }
|
|
||||||
.tabs-container > li.active {
|
|
||||||
border: 1px solid #333333;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.tabs-container > li.active:after {
|
|
||||||
top: 0 !important; right: auto !important;
|
|
||||||
width: 2px !important; height: auto !important;
|
|
||||||
background: #5c99f3 !important;
|
|
||||||
}
|
|
||||||
.tabs-container svg.close-icon #unsaved-circle-icon { fill: #5c99f3; }
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* 编辑器内容区 (v0.19.x 旧引擎: 容器是 #ag-editor-id)
|
|
||||||
* ==================================================================== */
|
|
||||||
|
|
||||||
/* ---- 标题 ---- */
|
|
||||||
#ag-editor-id h1 {
|
|
||||||
text-align: center;
|
|
||||||
padding-bottom: 0.3em;
|
|
||||||
}
|
|
||||||
#ag-editor-id h2 {
|
|
||||||
border-bottom: 2px solid var(--themeColor);
|
|
||||||
}
|
|
||||||
#ag-editor-id h3 {
|
|
||||||
border-left: 4px solid var(--themeColor);
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
#ag-editor-id h4 {
|
|
||||||
color: #ffffff !important;
|
|
||||||
background: var(--themeColor);
|
|
||||||
border-radius: 5px;
|
|
||||||
width: fit-content;
|
|
||||||
padding: 2px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 粗体 / 斜体 ---- */
|
|
||||||
#ag-editor-id strong { color: var(--strongColor); font-weight: 700; }
|
|
||||||
#ag-editor-id em { color: var(--emColor); }
|
|
||||||
|
|
||||||
/* ---- 链接 ---- */
|
|
||||||
#ag-editor-id a {
|
|
||||||
color: var(--linkColor);
|
|
||||||
font-weight: 700;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 行内代码 ---- */
|
|
||||||
#ag-editor-id code {
|
|
||||||
background-color: var(--codeBlockBgColor);
|
|
||||||
color: #eb4c37;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 2px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 代码块 ---- */
|
|
||||||
#ag-editor-id :not(pre) > code[class*='language-'],
|
|
||||||
#ag-editor-id pre:not(.CodeMirror-line),
|
|
||||||
#ag-editor-id pre[class*='language-'],
|
|
||||||
#ag-editor-id pre.ag-paragraph {
|
|
||||||
background: var(--codeBlockBgColor) !important;
|
|
||||||
border: none !important;
|
|
||||||
border-radius: 5px !important;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
||||||
transition: box-shadow 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 引用块 (四面边框 + 左侧加粗) ---- */
|
|
||||||
#ag-editor-id blockquote {
|
|
||||||
padding: 10px 10px 10px 20px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
border: 2px solid var(--blockquoteBorderColor);
|
|
||||||
border-left: 5px solid var(--blockquoteBorderColor);
|
|
||||||
border-radius: 0 5px 5px 0;
|
|
||||||
background: transparent;
|
|
||||||
overflow: auto;
|
|
||||||
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
|
||||||
}
|
|
||||||
#ag-editor-id blockquote:hover {
|
|
||||||
background: var(--editorBgColor);
|
|
||||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
/* 隐藏引擎默认的 ::before 竖条,改用 border-left */
|
|
||||||
#ag-editor-id blockquote::before {
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 分割线 ---- */
|
|
||||||
#ag-editor-id hr {
|
|
||||||
height: 2px;
|
|
||||||
background-color: var(--hrColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 表格 ---- */
|
|
||||||
#ag-editor-id table tr th::before,
|
|
||||||
#ag-editor-id table tr td::before {
|
|
||||||
border-color: var(--tableBorderColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 图片 ---- */
|
|
||||||
#ag-editor-id img {
|
|
||||||
border-radius: 10px;
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 任务列表复选框 ---- */
|
|
||||||
#ag-editor-id li.ag-task-list-item {
|
|
||||||
list-style-type: none;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#ag-editor-id li.ag-task-list-item > input[type='checkbox'] {
|
|
||||||
position: absolute;
|
|
||||||
cursor: pointer;
|
|
||||||
width: 16px; height: 16px; top: 0.1em;
|
|
||||||
margin: 0; left: -24px;
|
|
||||||
transform-origin: center;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
appearance: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
#ag-editor-id li.ag-task-list-item > input[type='checkbox']::before {
|
|
||||||
content: '';
|
|
||||||
width: 16px; height: 16px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: inline-block;
|
|
||||||
border: 2px solid var(--editorColor50);
|
|
||||||
border-radius: 2px;
|
|
||||||
background-color: var(--editorBgColor);
|
|
||||||
position: absolute; top: 0; left: 0;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
#ag-editor-id li.ag-task-list-item > input[type='checkbox']:checked::before {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: var(--themeColor);
|
|
||||||
}
|
|
||||||
#ag-editor-id li.ag-task-list-item > input[type='checkbox']::after {
|
|
||||||
content: '';
|
|
||||||
transform: rotate(-45deg) scale(0);
|
|
||||||
width: 9px; height: 5px;
|
|
||||||
border: 2px solid #fff;
|
|
||||||
border-top: none; border-right: none;
|
|
||||||
position: absolute; display: inline-block;
|
|
||||||
top: 1px; left: 5px;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
#ag-editor-id li.ag-task-list-item > input[type='checkbox']:checked::after {
|
|
||||||
transform: rotate(-45deg) scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 段落悬停 ---- */
|
|
||||||
#ag-editor-id p.ag-paragraph {
|
|
||||||
padding: 5px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: 5px;
|
|
||||||
transition: background-color 0.3s ease, box-shadow 0.3s ease;
|
|
||||||
}
|
|
||||||
#ag-editor-id p.ag-paragraph:hover {
|
|
||||||
background: #141414;
|
|
||||||
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 已完成任务文字 ---- */
|
|
||||||
#ag-editor-id li.ag-task-list-item > input.ag-checkbox-checked ~ * {
|
|
||||||
color: var(--editorColor50);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 列表标记 ---- */
|
|
||||||
#ag-editor-id ul > li::marker,
|
|
||||||
#ag-editor-id ol > li::marker {
|
|
||||||
color: var(--listMarkerColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 搜索高亮 ---- */
|
|
||||||
.ag-highlight {
|
|
||||||
background: #ff0 !important;
|
|
||||||
color: red !important;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 0 2px;
|
|
||||||
height: auto !important;
|
|
||||||
line-height: inherit !important;
|
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 表格表头 ---- */
|
|
||||||
#ag-editor-id table tr th {
|
|
||||||
background: var(--editorColor04);
|
|
||||||
}
|
|
||||||
#ag-editor-id table tr:first-child td {
|
|
||||||
background: var(--editorColor04);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 脚注 ---- */
|
|
||||||
#ag-editor-id sup.md-footnote {
|
|
||||||
color: var(--strongColor);
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- 前置图标 ---- */
|
|
||||||
.ag-front-icon {
|
|
||||||
fill: var(--editorColor30);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* CodeMirror 源码模式 (v0.19.x 旧引擎)
|
|
||||||
* ==================================================================== */
|
|
||||||
.source-code {
|
|
||||||
background: var(--editorBgColor);
|
|
||||||
}
|
|
||||||
.source-code .CodeMirror {
|
|
||||||
color: var(--editorColor);
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
.source-code .CodeMirror-gutters {
|
|
||||||
background: transparent;
|
|
||||||
border-right-color: #333333;
|
|
||||||
}
|
|
||||||
.source-code .CodeMirror-linenumber {
|
|
||||||
color: var(--editorColor30);
|
|
||||||
}
|
|
||||||
.source-code .CodeMirror-cursor {
|
|
||||||
border-left-color: var(--themeColor);
|
|
||||||
}
|
|
||||||
.source-code .CodeMirror-activeline-background {
|
|
||||||
background: var(--editorColor04);
|
|
||||||
}
|
|
||||||
.source-code .CodeMirror-selected {
|
|
||||||
background: var(--selectionColor) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CodeMirror 语法高亮色 — 参考 onelight 配色 */
|
|
||||||
.cm-s-one-dark .cm-comment { color: #7f848e; font-style: italic; }
|
|
||||||
.cm-s-one-dark .cm-keyword { color: #c678dd; }
|
|
||||||
.cm-s-one-dark .cm-operator { color: #56b6c2; }
|
|
||||||
.cm-s-one-dark .cm-builtin { color: #e5c07b; }
|
|
||||||
.cm-s-one-dark .cm-atom { color: #d19a66; }
|
|
||||||
.cm-s-one-dark .cm-number { color: #d19a66; }
|
|
||||||
.cm-s-one-dark .cm-def { color: #61afef; }
|
|
||||||
.cm-s-one-dark .cm-string { color: #98c379; }
|
|
||||||
.cm-s-one-dark .cm-string-2 { color: #e06c75; }
|
|
||||||
.cm-s-one-dark .cm-variable { color: #e06c75; }
|
|
||||||
.cm-s-one-dark .cm-variable-2 { color: #e5c07b; }
|
|
||||||
.cm-s-one-dark .cm-variable-3 { color: #d19a66; }
|
|
||||||
.cm-s-one-dark .cm-type { color: #e5c07b; }
|
|
||||||
.cm-s-one-dark .cm-meta { color: #e06c75; }
|
|
||||||
.cm-s-one-dark .cm-attribute { color: #d19a66; }
|
|
||||||
.cm-s-one-dark .cm-property { color: #e06c75; }
|
|
||||||
.cm-s-one-dark .cm-qualifier { color: #e5c07b; }
|
|
||||||
.cm-s-one-dark .cm-tag { color: #e06c75; }
|
|
||||||
.cm-s-one-dark .cm-link { color: #c678dd; }
|
|
||||||
.cm-s-one-dark .cm-header { color: #61afef; }
|
|
||||||
.cm-s-one-dark .cm-quote { color: #98c379; }
|
|
||||||
|
|
||||||
/* ====================================================================
|
|
||||||
* Mermaid/图表 SVG 暗色适配
|
|
||||||
* ==================================================================== */
|
|
||||||
figure[data-role] svg rect[fill='#ffffff'] { fill: var(--editorBgColor); }
|
|
||||||
figure[data-role] svg rect[stroke='#000000'] { stroke: var(--editorColor); }
|
|
||||||
figure[data-role] svg text[fill='#000000'] { fill: var(--editorColor); }
|
|
||||||
figure[data-role] svg path[stroke='#000000'] { stroke: var(--editorColor); }
|
|
||||||
figure[data-role] svg path[fill='#ffffff'] { fill: var(--editorBgColor); }
|
|
||||||
figure[data-role] svg path[fill='#000000'] { fill: var(--editorColor); }
|
|
||||||
figure[data-role] svg use[fill='black'] { fill: var(--editorColor); }
|
|
||||||
figure[data-role] svg use[fill='#000000'] { fill: var(--editorColor); }
|
|
||||||
|
|
||||||
```
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
# 正则表达式
|
|
||||||
|
|
||||||
正则表达式是一种用于匹配和操作文本的强大工具,用于描述要匹配的文本模式。
|
|
||||||
|
|
||||||
## 匹配字符
|
|
||||||
|
|
||||||
### 普通匹配字符
|
|
||||||
|
|
||||||
| 字符 | 描述 |
|
|
||||||
| :------- | :----------------------------------------------------------- |
|
|
||||||
| `[xyz]` | 匹配 `[xyz]` 中列出的所有字符。例如 `[xyz]`,能够匹配目标的所有 x、y、z 字符。 |
|
|
||||||
| `[^xyz]` | 匹配 `[^xyz]` 中列出的字符外的所有字符。例如 `[^xyz]`,能够匹配目标的除去 x、y、z 外的所有字符。 |
|
|
||||||
| `[A-Z]` | `[A-Z]` 表示一个区间,匹配所有大写字母;`[a-z]` 匹配所有小写字母;`[0-9]` 匹配所有数字。 |
|
|
||||||
| `[\s\S]` | 匹配所有字符(包括换行符)。`\s` 匹配所有空白符(包括换行),`\S` 匹配所有非空白符(不包括换行),两者合并即可匹配任意字符。 |
|
|
||||||
| `.` | 匹配除换行符 `\n`、`\r` 之外的任何单个字符,等价于 `[^\n\r]`。 |
|
|
||||||
| `\w` | 匹配字母、数字、下划线,等价于 `[A-Za-z0-9_]`。 |
|
|
||||||
| `\d` | 匹配任意一个阿拉伯数字(0 到 9),等价于 `[0-9]`。 |
|
|
||||||
|
|
||||||
### 非打印字符
|
|
||||||
|
|
||||||
| 字符 | 描述 |
|
|
||||||
| :---- | :----------------------------------------------------------- |
|
|
||||||
| `\cx` | 匹配由 x 指明的控制字符。例如,`\cM` 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一,否则将 c 视为一个原义的 'c' 字符。 |
|
|
||||||
| `\f` | 匹配一个换页符,等价于 `\x0c` 和 `\cL`。 |
|
|
||||||
| `\n` | 匹配一个换行符,等价于 `\x0a` 和 `\cJ`。 |
|
|
||||||
| `\r` | 匹配一个回车符,等价于 `\x0d` 和 `\cM`。 |
|
|
||||||
| `\s` | 匹配任何空白字符,包括空格、制表符、换页符等,等价于 `[ \f\n\r\t\v]`。注意 Unicode 正则表达式会匹配全角空格符。 |
|
|
||||||
| `\S` | 匹配任何非空白字符,等价于 `[^ \f\n\r\t\v]`。 |
|
|
||||||
| `\t` | 匹配一个制表符,等价于 `\x09` 和 `\cI`。 |
|
|
||||||
| `\v` | 匹配一个垂直制表符,等价于 `\x0b` 和 `\cK`。 |
|
|
||||||
|
|
||||||
### 特殊字符
|
|
||||||
|
|
||||||
| 特殊字符 | 描述 |
|
|
||||||
| :------- | :----------------------------------------------------------- |
|
|
||||||
| `$` | 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 `$` 也匹配 `\n` 或 `\r`。要匹配 `$` 字符本身,请使用 `\$`。 |
|
|
||||||
| `( )` | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 `\(` 和 `\)`。 |
|
|
||||||
| `*` | 匹配前面的子表达式零次或多次。要匹配 `*` 字符本身,请使用 `\*`。 |
|
|
||||||
| `+` | 匹配前面的子表达式一次或多次。要匹配 `+` 字符本身,请使用 `\+`。 |
|
|
||||||
| `.` | 匹配除换行符 `\n` 之外的任何单字符。要匹配 `.` 本身,请使用 `\.`。 |
|
|
||||||
| `[` | 标记一个中括号表达式的开始。要匹配 `[`,请使用 `\[`。 |
|
|
||||||
| `?` | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 `?` 字符本身,请使用 `\?`。 |
|
|
||||||
| `\` | 将下一个字符标记为特殊字符、原义字符、向后引用或八进制转义符。例如,`\\` 匹配 `\`。 |
|
|
||||||
| `^` | 匹配输入字符串的开始位置。在方括号表达式中使用时,表示不接受方括号内的字符集合(取反)。要匹配 `^` 字符本身,请使用 `\^`。 |
|
|
||||||
| `{` | 标记限定符表达式的开始。要匹配 `{`,请使用 `\{`。 |
|
|
||||||
| `|` | 指明两项之间的一个选择。要匹配 `|`,请使用 `\|`。 |
|
|
||||||
|
|
||||||
### 限定符
|
|
||||||
|
|
||||||
| 字符 | 描述 |
|
|
||||||
| :------ | :----------------------------------------------------------- |
|
|
||||||
| `*` | 匹配前面的子表达式零次或多次。 |
|
|
||||||
| `+` | 匹配前面的子表达式一次或多次。 |
|
|
||||||
| `?` | 匹配前面的子表达式零次或一次,等价于 `{0,1}`。例如,`do(es)?` 可以匹配 "do" 和 "does",但不能匹配 "dog"。 |
|
|
||||||
| `{n}` | n 是一个非负整数,匹配确定的 n 次。例如,`o{2}` 不能匹配 "Bob" 中的 o,但是能匹配 "food" 中的两个 o。 |
|
|
||||||
| `{n,}` | n 是一个非负整数,至少匹配 n 次。例如,`o{2,}` 不能匹配 "Bob" 中的 o,但能匹配 "foooood" 中的所有 o。`o{1,}` 等价于 `o+`,`o{0,}` 等价于 `o*`。 |
|
|
||||||
| `{n,m}` | m 和 n 均为非负整数,其中 n <= m。最少匹配 n 次且最多匹配 m 次。例如,`o{1,3}` 将匹配 "fooooood" 中的前三个 o。`o{0,1}` 等价于 `o?`。 |
|
|
||||||
|
|
||||||
## 常用正则表达式
|
|
||||||
|
|
||||||
| 正则表达式 | 匹配内容 |
|
|
||||||
| -------------------------- | ---------- |
|
|
||||||
| `[\u4e00-\u9fa5]` | 中文字符 |
|
|
||||||
| `\d{3}-\d{8}|\d{4}-\{7,8}` | 国内手机号 |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
| | |
|
|
||||||
|
|
||||||
@ -1,9 +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)
|
[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)
|
||||||
|
|
||||||
[Typora自定义主题](https://theme.typora.io/doc/zh/Write-Custom-Theme/)
|
|
||||||
|
|
||||||
> 通过自定义的CSS变量来实现
|
|
||||||
|
|
||||||
[CSDN增强助手](https://chromewebstore.google.com/detail/csdn%E5%A2%9E%E5%BC%BA%E5%8A%A9%E6%89%8B/fpgaealcfgjbodghojppfmohfcoajled)
|
|
||||||
|
|
||||||
> 能够智能屏蔽CSDN搜索结果、屏蔽其广告、自动展开代码
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user