Compare commits
10 Commits
69d4197074
...
52c7e98986
| Author | SHA1 | Date | |
|---|---|---|---|
| 52c7e98986 | |||
| 7422eb7346 | |||
| cd4a5a20ee | |||
| 26c9b207af | |||
| a7132b4779 | |||
| 0292147403 | |||
| ac33e1197b | |||
| b8bbd7d49e | |||
| 5b0f8b9cde | |||
| df678ecd83 |
+9
-3
@@ -1,7 +1,13 @@
|
|||||||
# Obsidian local state
|
# Obsidian local state
|
||||||
.obsidian/workspace.json
|
/.obsidian/workspace*.json
|
||||||
.obsidian/cache/
|
/.obsidian/cache/
|
||||||
密码本
|
/.vs/
|
||||||
|
/密码本/
|
||||||
|
/服务器迁移/
|
||||||
|
/Ignore/
|
||||||
|
/简历/
|
||||||
|
/日记/
|
||||||
|
|
||||||
|
|
||||||
# OS files
|
# OS files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
Vendored
+8
@@ -16,5 +16,13 @@
|
|||||||
],
|
],
|
||||||
"key": "X"
|
"key": "X"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"insert-template": [
|
||||||
|
{
|
||||||
|
"modifiers": [
|
||||||
|
"Alt"
|
||||||
|
],
|
||||||
|
"key": "T"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
-242
@@ -1,242 +0,0 @@
|
|||||||
{
|
|
||||||
"main": {
|
|
||||||
"id": "a693de761d542948",
|
|
||||||
"type": "split",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "de35c53ad452014d",
|
|
||||||
"type": "tabs",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "e7c250592202ef1d",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "markdown",
|
|
||||||
"state": {
|
|
||||||
"file": "待办/Unity重学.md",
|
|
||||||
"mode": "source",
|
|
||||||
"source": false
|
|
||||||
},
|
|
||||||
"icon": "lucide-file",
|
|
||||||
"title": "Unity重学"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"direction": "vertical"
|
|
||||||
},
|
|
||||||
"left": {
|
|
||||||
"id": "630f8165e6a24a86",
|
|
||||||
"type": "split",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "f0756957054a6fce",
|
|
||||||
"type": "tabs",
|
|
||||||
"dimension": 79.77755308392315,
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "ebc68222154201be",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "file-explorer",
|
|
||||||
"state": {
|
|
||||||
"sortOrder": "byModifiedTime",
|
|
||||||
"autoReveal": false
|
|
||||||
},
|
|
||||||
"icon": "lucide-folder-closed",
|
|
||||||
"title": "文件列表"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "991397493df067e8",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "bookmarks",
|
|
||||||
"state": {},
|
|
||||||
"icon": "lucide-bookmark",
|
|
||||||
"title": "书签"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cc621346ccdf86c9",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "outline",
|
|
||||||
"state": {
|
|
||||||
"file": "笔记/Unity笔记汇总.md",
|
|
||||||
"followCursor": false,
|
|
||||||
"showSearch": false,
|
|
||||||
"searchQuery": ""
|
|
||||||
},
|
|
||||||
"icon": "lucide-list",
|
|
||||||
"title": "Unity笔记汇总 的大纲"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "f8fdc77a59b98c85",
|
|
||||||
"type": "tabs",
|
|
||||||
"dimension": 20.222446916076844,
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "ecccd9af8286ea29",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "search",
|
|
||||||
"state": {
|
|
||||||
"query": "[\"tags\"]",
|
|
||||||
"matchingCase": false,
|
|
||||||
"explainSearch": false,
|
|
||||||
"collapseAll": false,
|
|
||||||
"extraContext": false,
|
|
||||||
"sortOrder": "alphabetical"
|
|
||||||
},
|
|
||||||
"icon": "lucide-search",
|
|
||||||
"title": "搜索"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"direction": "horizontal",
|
|
||||||
"width": 300
|
|
||||||
},
|
|
||||||
"right": {
|
|
||||||
"id": "c7920e2ce907397e",
|
|
||||||
"type": "split",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "a5f3c68213ee3916",
|
|
||||||
"type": "tabs",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "42aa94a29399c26f",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "backlink",
|
|
||||||
"state": {
|
|
||||||
"file": "笔记/Unity笔记汇总.md",
|
|
||||||
"collapseAll": false,
|
|
||||||
"extraContext": false,
|
|
||||||
"sortOrder": "alphabetical",
|
|
||||||
"showSearch": false,
|
|
||||||
"searchQuery": "",
|
|
||||||
"backlinkCollapsed": false,
|
|
||||||
"unlinkedCollapsed": true
|
|
||||||
},
|
|
||||||
"icon": "links-coming-in",
|
|
||||||
"title": "Unity笔记汇总 的反向链接列表"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "d651b27dcd912ace",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "outgoing-link",
|
|
||||||
"state": {
|
|
||||||
"file": "笔记/CSharp/核心/索引器.md",
|
|
||||||
"linksCollapsed": false,
|
|
||||||
"unlinkedCollapsed": false
|
|
||||||
},
|
|
||||||
"icon": "links-going-out",
|
|
||||||
"title": "索引器 的出链列表"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "b395181a320df62d",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "tag",
|
|
||||||
"state": {
|
|
||||||
"sortOrder": "frequency",
|
|
||||||
"useHierarchy": true,
|
|
||||||
"showSearch": false,
|
|
||||||
"searchQuery": ""
|
|
||||||
},
|
|
||||||
"icon": "lucide-tags",
|
|
||||||
"title": "标签"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "d9c193444d1f152f",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "all-properties",
|
|
||||||
"state": {
|
|
||||||
"sortOrder": "frequency",
|
|
||||||
"showSearch": false,
|
|
||||||
"searchQuery": ""
|
|
||||||
},
|
|
||||||
"icon": "lucide-archive",
|
|
||||||
"title": "添加笔记属性"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"currentTab": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"direction": "horizontal",
|
|
||||||
"width": 200
|
|
||||||
},
|
|
||||||
"left-ribbon": {
|
|
||||||
"hiddenItems": {
|
|
||||||
"switcher:打开快速切换": false,
|
|
||||||
"graph:查看关系图谱": false,
|
|
||||||
"canvas:新建白板": false,
|
|
||||||
"daily-notes:打开/创建今天的日记": false,
|
|
||||||
"templates:插入模板": false,
|
|
||||||
"command-palette:打开命令面板": false,
|
|
||||||
"bases:新建数据库": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"active": "e7c250592202ef1d",
|
|
||||||
"lastOpenFiles": [
|
|
||||||
"笔记/CSharp笔记汇总.md",
|
|
||||||
"待办/Unity重学.md",
|
|
||||||
"待办/CSharp重学.md",
|
|
||||||
"笔记/CSharp/进阶/Hashtable.md",
|
|
||||||
"笔记/CSharp/进阶/Stack.md",
|
|
||||||
"简历_综合应届生版.md",
|
|
||||||
"简历_网络运维技术支持方向.md",
|
|
||||||
"服务器迁移/网站容器迁移与SSL续签手册.md",
|
|
||||||
"简历_Unity游戏开发方向.md",
|
|
||||||
"密码本/Teamspeak Recovery Key.md",
|
|
||||||
"Teamspeak/网站容器迁移与SSL续签手册.md",
|
|
||||||
"笔记/CSharp/基础/值类型和引用类型.md",
|
|
||||||
"笔记/CSharp/入门/字符串拼接.md",
|
|
||||||
"待办/大待办.md",
|
|
||||||
"未命名.md",
|
|
||||||
"未命名 1.md",
|
|
||||||
"服务器迁移",
|
|
||||||
"笔记/CSharp/进阶/Queue.md",
|
|
||||||
"笔记/CSharp/进阶/ArrayList.md",
|
|
||||||
"笔记/Unity笔记汇总.md",
|
|
||||||
"笔记/CSharp/练习/CSharp综合练习-02.md",
|
|
||||||
"笔记/CSharp/进阶",
|
|
||||||
"笔记/CSharp/核心/索引器.md",
|
|
||||||
"笔记/CSharp/核心/接口.md",
|
|
||||||
"笔记/CSharp/基础/枚举.md",
|
|
||||||
"笔记/CSharp/核心/抽象类和抽象方法.md",
|
|
||||||
"笔记/CSharp/核心/密封函数.md",
|
|
||||||
"笔记/CSharp/核心/密封类.md",
|
|
||||||
"未命名.base",
|
|
||||||
"未命名.canvas",
|
|
||||||
"密码本",
|
|
||||||
"图库/CSharp/Pasted image 20260412210327.png",
|
|
||||||
"笔记/CSharp/练习",
|
|
||||||
"图库/CSharp/Pasted image 20260412210704.png",
|
|
||||||
"图库/CSharp/Pasted image 20260412210810.png",
|
|
||||||
"图库/CSharp/Pasted image 20260412210946.png",
|
|
||||||
"笔记/CSharp/杂记",
|
|
||||||
"Pasted image 20260412210946.png",
|
|
||||||
"Pasted image 20260412210810.png",
|
|
||||||
"Pasted image 20260412210704.png",
|
|
||||||
"图库/CSharp/Pasted image 20260412210516.png",
|
|
||||||
"图库/CSharp",
|
|
||||||
"图库",
|
|
||||||
"笔记/CSharp/核心",
|
|
||||||
"笔记/CSharp/基础"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"Version": 1,
|
|
||||||
"WorkspaceRootPath": "E:\\Obsidian\\OneDrive\\Apps\\remotely-save\\MyNotes\\",
|
|
||||||
"Documents": [],
|
|
||||||
"DocumentGroupContainers": [
|
|
||||||
{
|
|
||||||
"Orientation": 0,
|
|
||||||
"VerticalTabListWidth": 256,
|
|
||||||
"DocumentGroups": [
|
|
||||||
{
|
|
||||||
"DockedWidth": 200,
|
|
||||||
"SelectedChildIndex": -1,
|
|
||||||
"Children": [
|
|
||||||
{
|
|
||||||
"$type": "Bookmark",
|
|
||||||
"Name": "ST:128:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Bookmark",
|
|
||||||
"Name": "ST:129:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Bookmark",
|
|
||||||
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"Version": 1,
|
|
||||||
"WorkspaceRootPath": "E:\\Obsidian\\OneDrive\\Apps\\remotely-save\\MyNotes\\",
|
|
||||||
"Documents": [],
|
|
||||||
"DocumentGroupContainers": [
|
|
||||||
{
|
|
||||||
"Orientation": 0,
|
|
||||||
"VerticalTabListWidth": 256,
|
|
||||||
"DocumentGroups": [
|
|
||||||
{
|
|
||||||
"DockedWidth": 200,
|
|
||||||
"SelectedChildIndex": -1,
|
|
||||||
"Children": [
|
|
||||||
{
|
|
||||||
"$type": "Bookmark",
|
|
||||||
"Name": "ST:129:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$type": "Bookmark",
|
|
||||||
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"Version": 1,
|
|
||||||
"WorkspaceRootPath": "C:\\Users\\Kister\\OneDrive\\Apps\\remotely-save\\MyNotes\\",
|
|
||||||
"Documents": [],
|
|
||||||
"DocumentGroupContainers": [
|
|
||||||
{
|
|
||||||
"Orientation": 0,
|
|
||||||
"VerticalTabListWidth": 256,
|
|
||||||
"DocumentGroups": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"Version": 1,
|
|
||||||
"WorkspaceRootPath": "C:\\Users\\Kister\\OneDrive\\Apps\\remotely-save\\MyNotes\\",
|
|
||||||
"Documents": [],
|
|
||||||
"DocumentGroupContainers": [
|
|
||||||
{
|
|
||||||
"Orientation": 0,
|
|
||||||
"VerticalTabListWidth": 256,
|
|
||||||
"DocumentGroups": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"CurrentProjectSetting": null
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"ExpandedNodes": [
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"PreviewInSolutionExplorer": false
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -48,3 +48,4 @@ sort by done reverse
|
|||||||
```
|
```
|
||||||
|
|
||||||
* 2026-06-20 - 2
|
* 2026-06-20 - 2
|
||||||
|
* 2026-06-22 - 2
|
||||||
+4
-3
@@ -28,9 +28,10 @@
|
|||||||
- [x] [[Stack]] #study/csharp
|
- [x] [[Stack]] #study/csharp
|
||||||
- [x] [[Queue]] #study/csharp
|
- [x] [[Queue]] #study/csharp
|
||||||
- [x] [[Hashtable]] #study/csharp
|
- [x] [[Hashtable]] #study/csharp
|
||||||
- [ ] 泛型和泛型约束 #study/csharp
|
- [x] 泛型和泛型约束 #study/csharp
|
||||||
- [ ] List #study/csharp
|
- [x] List #study/csharp
|
||||||
- [ ] Dictionary #study/csharp
|
- [x] Dictionary #study/csharp
|
||||||
|
- [x] 顺序存储和链式存储 #study/csharp ✅ 2026-06-24
|
||||||
- [ ] LinkedList #study/csharp
|
- [ ] LinkedList #study/csharp
|
||||||
- [ ] 泛型栈和队列 #study/csharp
|
- [ ] 泛型栈和队列 #study/csharp
|
||||||
- [ ] 委托事件 #study/csharp
|
- [ ] 委托事件 #study/csharp
|
||||||
|
|||||||
@@ -1,14 +1,30 @@
|
|||||||
# 日常 List
|
# 日常 List
|
||||||
> 这里放每天会自动刷新的小任务。完成后 Tasks 会按 `🔁 every day` 生成下一次。
|
> 这里放每天会自动刷新的小任务。完成后 Tasks 会按 `🔁 every day` 生成下一次。
|
||||||
|
|
||||||
- [ ] eNSP #daily 🔺 🔁 every day 📅 2026-06-22
|
- [ ] 网工 #daily 🔺 🔁 every day 📅 2026-06-26
|
||||||
|
- [x] 网工 #daily 🔺 🔁 every day 📅 2026-06-24 ✅ 2026-06-24
|
||||||
|
- [x] eNSP #daily 🔺 🔁 every day 📅 2026-06-23 ✅ 2026-06-23
|
||||||
|
- [x] eNSP #daily 🔺 🔁 every day 📅 2026-06-22 ✅ 2026-06-22
|
||||||
- [x] eNSP #daily 🔺 🔁 every day 📅 2026-06-21 ✅ 2026-06-21
|
- [x] eNSP #daily 🔺 🔁 every day 📅 2026-06-21 ✅ 2026-06-21
|
||||||
- [ ] Linux #daily 🔺 🔁 every day 📅 2026-06-22
|
- [ ] Linux #daily 🔺 🔁 every day 📅 2026-06-26
|
||||||
|
- [x] Linux #daily 🔺 🔁 every day 📅 2026-06-24 ✅ 2026-06-24
|
||||||
|
- [x] Linux #daily 🔺 🔁 every day 📅 2026-06-23 ✅ 2026-06-23
|
||||||
|
- [x] Linux #daily 🔺 🔁 every day 📅 2026-06-22 ✅ 2026-06-22
|
||||||
- [x] Linux #daily 🔺 🔁 every day 📅 2026-06-21 ✅ 2026-06-21
|
- [x] Linux #daily 🔺 🔁 every day 📅 2026-06-21 ✅ 2026-06-21
|
||||||
- [ ] C# #daily ⏫ 🔁 every day 📅 2026-06-21
|
- [ ] C# #daily ⏫ 🔁 every day 📅 2026-06-26
|
||||||
|
- [x] C# #daily ⏫ 🔁 every day 📅 2026-06-24 ✅ 2026-06-24
|
||||||
|
- [x] C# #daily ⏫ 🔁 every day 📅 2026-06-22 ✅ 2026-06-22
|
||||||
|
- [x] C# #daily ⏫ 🔁 every day 📅 2026-06-21 ✅ 2026-06-22
|
||||||
- [ ] C++ 或 UE #weekly ⏬ 🔁 every week
|
- [ ] C++ 或 UE #weekly ⏬ 🔁 every week
|
||||||
- [ ] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-21
|
- [ ] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-26
|
||||||
- [ ] 学习吉他 🔼 🔁 every day 📅 2026-06-21
|
- [x] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-23 ✅ 2026-06-23
|
||||||
|
- [x] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-22 ✅ 2026-06-23
|
||||||
|
- [x] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-21 ✅ 2026-06-22
|
||||||
|
- [ ] 学习吉他 🔼 🔁 every day 📅 2026-06-26
|
||||||
|
- [x] 学习吉他 🔼 🔁 every day 📅 2026-06-24 ✅ 2026-06-24
|
||||||
|
- [x] 学习吉他 🔼 🔁 every day 📅 2026-06-23 ✅ 2026-06-23
|
||||||
|
- [x] 学习吉他 🔼 🔁 every day 📅 2026-06-22 ✅ 2026-06-23
|
||||||
|
- [x] 学习吉他 🔼 🔁 every day 📅 2026-06-21 ✅ 2026-06-22
|
||||||
- [x] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-20 ✅ 2026-06-20
|
- [x] 今日复盘:记录完成情况和明天第一件事 🔼 🔁 every day 📅 2026-06-20 ✅ 2026-06-20
|
||||||
|
|
||||||
## 显示今日的样例:
|
## 显示今日的样例:
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
|
||||||
|
作用:
|
||||||
|
|
||||||
|
参数:
|
||||||
|
-
|
||||||
|
|
||||||
|
示例:
|
||||||
|
-
|
||||||
+2
-1
@@ -18,7 +18,8 @@ sort by priority
|
|||||||
|
|
||||||
> ==记得把今日任务详细的规划在时间线上↓==
|
> ==记得把今日任务详细的规划在时间线上↓==
|
||||||
|
|
||||||
- [ ] 09:00 - 09:30
|
- [ ] 14:40 - 15:40 eNSP
|
||||||
|
- [ ] 复盘
|
||||||
|
|
||||||
## 复盘
|
## 复盘
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,409 @@
|
|||||||
|
# Dictionary
|
||||||
|
概念:
|
||||||
|
`Dictionary<TKey, TValue>` 是 C# 提供的==泛型键值对集合==
|
||||||
|
它通过键 `key` 来快速查找值 `value`
|
||||||
|
|
||||||
|
简单理解:
|
||||||
|
像一本字典
|
||||||
|
用“词”查“解释”
|
||||||
|
用 `key` 查 `value`
|
||||||
|
|
||||||
|
命名空间:
|
||||||
|
```csharp
|
||||||
|
using System.Collections.Generic;
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 通常用法
|
||||||
|
1. 保存键值对数据
|
||||||
|
2. 通过唯一键快速查找对应值
|
||||||
|
3. 根据 `id`、名字、编号等信息管理对象
|
||||||
|
4. 替代早期非泛型键值对集合 `Hashtable`
|
||||||
|
|
||||||
|
实际开发中:
|
||||||
|
`Dictionary<TKey, TValue>` 非常常用
|
||||||
|
只要需求是“通过 key 快速找到 value”
|
||||||
|
通常都可以先考虑它
|
||||||
|
|
||||||
|
----
|
||||||
|
# 语法
|
||||||
|
创建:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
```
|
||||||
|
|
||||||
|
添加:
|
||||||
|
```csharp
|
||||||
|
dict.Add("语文", 90);
|
||||||
|
```
|
||||||
|
|
||||||
|
通过键取值:
|
||||||
|
```csharp
|
||||||
|
int score = dict["语文"];
|
||||||
|
```
|
||||||
|
|
||||||
|
修改:
|
||||||
|
```csharp
|
||||||
|
dict["语文"] = 95;
|
||||||
|
```
|
||||||
|
|
||||||
|
数量:
|
||||||
|
```csharp
|
||||||
|
dict.Count
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 基础案例
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
Dictionary<string, int> scores = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
scores.Add("语文", 90);
|
||||||
|
scores.Add("数学", 95);
|
||||||
|
scores.Add("英语", 88);
|
||||||
|
|
||||||
|
Console.WriteLine(scores["语文"]);
|
||||||
|
Console.WriteLine(scores["数学"]);
|
||||||
|
Console.WriteLine(scores["英语"]);
|
||||||
|
Console.WriteLine(scores.Count);
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
```text
|
||||||
|
90
|
||||||
|
95
|
||||||
|
88
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
1. `"语文"`、`"数学"`、`"英语"` 是键
|
||||||
|
2. `90`、`95`、`88` 是值
|
||||||
|
3. 通过 key 能快速找到对应 value
|
||||||
|
|
||||||
|
----
|
||||||
|
# Add 和索引器
|
||||||
|
使用 `Add` 添加:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
dict.Add("hp", 100);
|
||||||
|
dict.Add("mp", 50);
|
||||||
|
```
|
||||||
|
|
||||||
|
使用索引器新增或修改:
|
||||||
|
```csharp
|
||||||
|
dict["atk"] = 20; // key 不存在时,新增
|
||||||
|
dict["atk"] = 25; // key 已存在时,修改
|
||||||
|
```
|
||||||
|
|
||||||
|
区别:
|
||||||
|
1. `Add` 遇到重复 key 会报错
|
||||||
|
2. `dict[key] = value` 遇到重复 key 会覆盖旧值
|
||||||
|
|
||||||
|
----
|
||||||
|
# 增删查改
|
||||||
|
增加:
|
||||||
|
```csharp
|
||||||
|
dict.Add("def", 10);
|
||||||
|
```
|
||||||
|
|
||||||
|
删除:
|
||||||
|
```csharp
|
||||||
|
dict.Remove("def");
|
||||||
|
dict.Clear();
|
||||||
|
```
|
||||||
|
|
||||||
|
查找键:
|
||||||
|
```csharp
|
||||||
|
bool hasHp = dict.ContainsKey("hp");
|
||||||
|
```
|
||||||
|
|
||||||
|
查找值:
|
||||||
|
```csharp
|
||||||
|
bool hasValue = dict.ContainsValue(100);
|
||||||
|
```
|
||||||
|
|
||||||
|
修改:
|
||||||
|
```csharp
|
||||||
|
dict["hp"] = 120;
|
||||||
|
```
|
||||||
|
|
||||||
|
取值:
|
||||||
|
```csharp
|
||||||
|
int hp = dict["hp"];
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# TryGetValue 很常用
|
||||||
|
直接取值:
|
||||||
|
```csharp
|
||||||
|
int hp = dict["hp"];
|
||||||
|
```
|
||||||
|
|
||||||
|
问题:
|
||||||
|
如果 key 不存在
|
||||||
|
会报错
|
||||||
|
|
||||||
|
更稳的写法:
|
||||||
|
```csharp
|
||||||
|
if (dict.TryGetValue("hp", out int hp))
|
||||||
|
{
|
||||||
|
Console.WriteLine(hp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("没有这个键");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
1. `TryGetValue` 会返回 `true` 或 `false`
|
||||||
|
2. 如果找到 key,就把对应值放进 `out` 变量
|
||||||
|
3. 如果项目里经常“先查再取”,`TryGetValue` 很实用
|
||||||
|
|
||||||
|
----
|
||||||
|
# 遍历
|
||||||
|
遍历键值对:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
dict.Add("语文", 90);
|
||||||
|
dict.Add("数学", 95);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, int> item in dict)
|
||||||
|
{
|
||||||
|
Console.WriteLine(item.Key + " : " + item.Value);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
只遍历键:
|
||||||
|
```csharp
|
||||||
|
foreach (string key in dict.Keys)
|
||||||
|
{
|
||||||
|
Console.WriteLine(key);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
只遍历值:
|
||||||
|
```csharp
|
||||||
|
foreach (int value in dict.Values)
|
||||||
|
{
|
||||||
|
Console.WriteLine(value);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
复习时不要把 `Dictionary` 当成“按下标顺序排列的列表”
|
||||||
|
它的核心用途是通过 key 查 value
|
||||||
|
|
||||||
|
----
|
||||||
|
# key 不能重复
|
||||||
|
错误写法:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
dict.Add("hp", 100);
|
||||||
|
dict.Add("hp", 200);
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
`Dictionary` 中的 key 必须唯一
|
||||||
|
重复添加同一个 key 会报错
|
||||||
|
|
||||||
|
如果想修改旧值:
|
||||||
|
```csharp
|
||||||
|
dict["hp"] = 200;
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# key 一般不能为 null
|
||||||
|
错误写法:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
// dict.Add(null, 100);
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
`Dictionary` 的 key 不能为 `null`
|
||||||
|
|
||||||
|
补充:
|
||||||
|
如果 `TValue` 是引用类型或可空类型
|
||||||
|
value 可以是 `null`
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, string> dict = new Dictionary<string, string>();
|
||||||
|
dict["name"] = null;
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 和 Hashtable 的区别
|
||||||
|
`Hashtable`:
|
||||||
|
非泛型
|
||||||
|
key 和 value 都按 `object` 处理
|
||||||
|
取值时常常需要强制类型转换
|
||||||
|
|
||||||
|
`Dictionary<TKey, TValue>`:
|
||||||
|
泛型
|
||||||
|
key 和 value 类型明确
|
||||||
|
编译期就能检查类型错误
|
||||||
|
使用起来更安全,更常见
|
||||||
|
|
||||||
|
对比表:
|
||||||
|
|
||||||
|
| 对比点 | `Hashtable` | `Dictionary<TKey, TValue>` |
|
||||||
|
|---|---|---|
|
||||||
|
| 类型 | 非泛型 | 泛型 |
|
||||||
|
| 键和值 | `object` | 指定类型 |
|
||||||
|
| 类型安全 | 较弱 | 更强 |
|
||||||
|
| 取值 | 常要强转 | 一般不用强转 |
|
||||||
|
| 推荐程度 | 主要用于学习旧集合 | 实际开发常用 |
|
||||||
|
|
||||||
|
----
|
||||||
|
# 和 List 的区别
|
||||||
|
| 对比点 | `List<T>` | `Dictionary<TKey, TValue>` |
|
||||||
|
|---|---|---|
|
||||||
|
| 存储方式 | 单个元素 | 键值对 |
|
||||||
|
| 查找方式 | 常用下标 | 常用 key |
|
||||||
|
| key | 没有 | 必须唯一 |
|
||||||
|
| 适合场景 | 一组同类型数据 | 根据唯一键查数据 |
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
`List<T>` 更像“列表”
|
||||||
|
`Dictionary<TKey, TValue>` 更像“字典”
|
||||||
|
|
||||||
|
----
|
||||||
|
# 基础案例:角色表
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public int Level;
|
||||||
|
|
||||||
|
public Player(string name, int level)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Level = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Dictionary<int, Player> players = new Dictionary<int, Player>();
|
||||||
|
|
||||||
|
players.Add(1001, new Player("小明", 10));
|
||||||
|
players.Add(1002, new Player("小红", 12));
|
||||||
|
players.Add(1003, new Player("小刚", 8));
|
||||||
|
|
||||||
|
if (players.TryGetValue(1002, out Player player))
|
||||||
|
{
|
||||||
|
Console.WriteLine(player.Name + " " + player.Level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
```text
|
||||||
|
小红 12
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
1. `1001`、`1002`、`1003` 是玩家编号
|
||||||
|
2. 通过编号可以快速找到对应玩家对象
|
||||||
|
3. 这种“编号 -> 对象”的场景非常适合用 `Dictionary`
|
||||||
|
|
||||||
|
----
|
||||||
|
# 常用成员
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
dict.Add("A", 1);
|
||||||
|
dict["B"] = 2;
|
||||||
|
|
||||||
|
Console.WriteLine(dict.Count);
|
||||||
|
Console.WriteLine(dict.ContainsKey("A"));
|
||||||
|
Console.WriteLine(dict.ContainsValue(2));
|
||||||
|
|
||||||
|
dict.Remove("A");
|
||||||
|
dict.Clear();
|
||||||
|
```
|
||||||
|
|
||||||
|
常用方法 / 成员:
|
||||||
|
1. `Add(TKey key, TValue value)`:添加键值对
|
||||||
|
2. `Remove(TKey key)`:删除指定 key
|
||||||
|
3. `Clear()`:清空
|
||||||
|
4. `ContainsKey(TKey key)`:判断 key 是否存在
|
||||||
|
5. `ContainsValue(TValue value)`:判断 value 是否存在
|
||||||
|
6. `TryGetValue(TKey key, out TValue value)`:安全取值
|
||||||
|
7. `Keys`:获取所有键
|
||||||
|
8. `Values`:获取所有值
|
||||||
|
9. `Count`:键值对数量
|
||||||
|
10. `dict[key]`:通过 key 取值或赋值
|
||||||
|
|
||||||
|
----
|
||||||
|
# 注意
|
||||||
|
1. `Dictionary<TKey, TValue>` 在 `System.Collections.Generic` 命名空间中
|
||||||
|
2. 它是泛型键值对集合
|
||||||
|
3. key 必须唯一
|
||||||
|
4. `Add` 遇到重复 key 会报错
|
||||||
|
5. `dict[key] = value` 可以新增,也可以覆盖旧值
|
||||||
|
6. 用不存在的 key 直接取值可能报错
|
||||||
|
7. 更稳的取值方式通常是 `TryGetValue`
|
||||||
|
8. 它最核心的优势是“通过 key 快速找 value”
|
||||||
|
|
||||||
|
----
|
||||||
|
# 易错点
|
||||||
|
1. 不要把 `Dictionary` 当数组或 `List<T>` 来用
|
||||||
|
2. 不要默认 key 一定存在
|
||||||
|
3. `ContainsKey` 判断的是键,不是值
|
||||||
|
4. `ContainsValue` 可以用,但实际开发里更常关心 key
|
||||||
|
5. 重复 `Add` 同一个 key 会报错
|
||||||
|
|
||||||
|
错误示例:
|
||||||
|
```csharp
|
||||||
|
Dictionary<string, int> dict = new Dictionary<string, int>();
|
||||||
|
dict.Add("hp", 100);
|
||||||
|
|
||||||
|
// Console.WriteLine(dict["mp"]);
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
`"mp"` 这个 key 不存在
|
||||||
|
直接取值可能报错
|
||||||
|
|
||||||
|
----
|
||||||
|
# 一句话记忆
|
||||||
|
==Dictionary<TKey, TValue> 是通过唯一 key 快速查找 value 的泛型键值对集合。==
|
||||||
|
|
||||||
|
再压缩一点:
|
||||||
|
==List 用下标找,Dictionary 用 key 找。==
|
||||||
|
|
||||||
|
----
|
||||||
|
# 面试/复习时怎么说
|
||||||
|
可以这样答:
|
||||||
|
|
||||||
|
“`Dictionary<TKey, TValue>` 是 C# 中非常常用的泛型键值对集合,适合通过唯一 key 快速查找 value。
|
||||||
|
它的 key 不能重复,常用操作有 `Add`、`Remove`、`ContainsKey` 和 `TryGetValue`。
|
||||||
|
相比 `Hashtable`,`Dictionary` 类型更安全,不需要频繁强制类型转换,所以实际开发中更常用。”
|
||||||
|
|
||||||
|
----
|
||||||
|
引用:
|
||||||
|
1. Microsoft Learn: [Dictionary<TKey,TValue> Class](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-9.0)
|
||||||
|
2. Microsoft Learn: [Dictionary<TKey,TValue>.TryGetValue Method](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.trygetvalue?view=net-9.0)
|
||||||
|
3. Microsoft Learn: [System.Collections.Generic Namespace](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic?view=net-9.0)
|
||||||
|
|
||||||
|
#Dictionary
|
||||||
|
#字典
|
||||||
|
#泛型集合
|
||||||
|
#集合
|
||||||
|
#进阶
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
# List
|
||||||
|
概念:
|
||||||
|
`List<T>` 是 C# 提供的==泛型集合类==
|
||||||
|
本质上可以理解为:==一个长度可变的泛型数组==
|
||||||
|
|
||||||
|
它可以:
|
||||||
|
1. 按下标访问元素
|
||||||
|
2. 自动扩容
|
||||||
|
3. 方便地增删查改
|
||||||
|
4. 保证集合中元素类型统一
|
||||||
|
|
||||||
|
命名空间:
|
||||||
|
```csharp
|
||||||
|
using System.Collections.Generic;
|
||||||
|
```
|
||||||
|
|
||||||
|
简单理解:
|
||||||
|
数组长度固定
|
||||||
|
`List<T>` 长度可以动态变化
|
||||||
|
而且比 `ArrayList` 更安全,因为它有明确类型
|
||||||
|
|
||||||
|
----
|
||||||
|
# 通常用法
|
||||||
|
1. 存储数量不固定的一组同类型数据
|
||||||
|
2. 需要频繁添加、删除、遍历元素
|
||||||
|
3. 作为项目里最常见的基础集合之一
|
||||||
|
4. 替代早期非泛型集合 `ArrayList`
|
||||||
|
|
||||||
|
实际开发中:
|
||||||
|
新项目里 `List<T>` 的使用频率非常高
|
||||||
|
很多时候它就是“默认列表容器”
|
||||||
|
|
||||||
|
----
|
||||||
|
# 语法
|
||||||
|
创建:
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>();
|
||||||
|
```
|
||||||
|
|
||||||
|
创建并赋初值:
|
||||||
|
```csharp
|
||||||
|
List<string> names = new List<string>() { "小明", "小红", "小刚" };
|
||||||
|
```
|
||||||
|
|
||||||
|
添加:
|
||||||
|
```csharp
|
||||||
|
list.Add(10);
|
||||||
|
```
|
||||||
|
|
||||||
|
访问:
|
||||||
|
```csharp
|
||||||
|
list[0]
|
||||||
|
```
|
||||||
|
|
||||||
|
数量:
|
||||||
|
```csharp
|
||||||
|
list.Count
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 基础案例
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
List<int> list = new List<int>();
|
||||||
|
|
||||||
|
list.Add(10);
|
||||||
|
list.Add(20);
|
||||||
|
list.Add(30);
|
||||||
|
|
||||||
|
Console.WriteLine(list[0]);
|
||||||
|
Console.WriteLine(list[1]);
|
||||||
|
Console.WriteLine(list[2]);
|
||||||
|
Console.WriteLine(list.Count);
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
```text
|
||||||
|
10
|
||||||
|
20
|
||||||
|
30
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
1. `List<int>` 里只能放 `int`
|
||||||
|
2. 可以像数组一样通过下标访问
|
||||||
|
3. `Count` 表示当前实际元素个数
|
||||||
|
|
||||||
|
----
|
||||||
|
# 和 ArrayList 的区别
|
||||||
|
`ArrayList`:
|
||||||
|
内部按 `object` 存储
|
||||||
|
可以混合存很多类型
|
||||||
|
取值时常常需要强制类型转换
|
||||||
|
值类型放进去会发生装箱拆箱
|
||||||
|
|
||||||
|
`List<T>`:
|
||||||
|
内部是泛型集合
|
||||||
|
类型更明确
|
||||||
|
编译期就能检查类型错误
|
||||||
|
通常不会像 `ArrayList` 那样频繁发生装箱拆箱
|
||||||
|
|
||||||
|
对比表:
|
||||||
|
|
||||||
|
| 对比点 | `ArrayList` | `List<T>` |
|
||||||
|
|---|---|---|
|
||||||
|
| 类型 | 非泛型 | 泛型 |
|
||||||
|
| 存储 | `object` | 指定类型 `T` |
|
||||||
|
| 类型安全 | 较弱 | 更强 |
|
||||||
|
| 取值 | 常要强转 | 一般不用强转 |
|
||||||
|
| 性能 | 值类型可能有装箱拆箱 | 通常更好 |
|
||||||
|
| 推荐程度 | 主要用于学习旧集合 | 实际开发常用 |
|
||||||
|
|
||||||
|
----
|
||||||
|
# 增删查改
|
||||||
|
增加:
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>();
|
||||||
|
|
||||||
|
list.Add(1);
|
||||||
|
list.Add(2);
|
||||||
|
list.Add(3);
|
||||||
|
|
||||||
|
list.Insert(1, 99);
|
||||||
|
list.AddRange(new List<int> { 7, 8, 9 });
|
||||||
|
```
|
||||||
|
|
||||||
|
删除:
|
||||||
|
```csharp
|
||||||
|
list.Remove(2); // 删除第一个匹配到的元素
|
||||||
|
list.RemoveAt(0); // 删除指定下标元素
|
||||||
|
list.Clear(); // 清空整个列表
|
||||||
|
```
|
||||||
|
|
||||||
|
查找:
|
||||||
|
```csharp
|
||||||
|
bool hasValue = list.Contains(99);
|
||||||
|
int index1 = list.IndexOf(99);
|
||||||
|
int index2 = list.LastIndexOf(99);
|
||||||
|
```
|
||||||
|
|
||||||
|
修改:
|
||||||
|
```csharp
|
||||||
|
list[0] = 100;
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 遍历
|
||||||
|
使用 `for`:
|
||||||
|
```csharp
|
||||||
|
List<string> names = new List<string>() { "A", "B", "C" };
|
||||||
|
|
||||||
|
for (int i = 0; i < names.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine(names[i]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 `foreach`:
|
||||||
|
```csharp
|
||||||
|
foreach (string item in names)
|
||||||
|
{
|
||||||
|
Console.WriteLine(item);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
如果只是读取元素,`foreach` 写起来更方便
|
||||||
|
如果需要下标,通常用 `for`
|
||||||
|
|
||||||
|
----
|
||||||
|
# Count 和 Capacity
|
||||||
|
`Count`:
|
||||||
|
当前实际有多少个元素
|
||||||
|
|
||||||
|
`Capacity`:
|
||||||
|
内部数组当前能容纳多少个元素
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>();
|
||||||
|
|
||||||
|
Console.WriteLine(list.Count);
|
||||||
|
Console.WriteLine(list.Capacity);
|
||||||
|
|
||||||
|
list.Add(10);
|
||||||
|
list.Add(20);
|
||||||
|
|
||||||
|
Console.WriteLine(list.Count);
|
||||||
|
Console.WriteLine(list.Capacity);
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
`List<T>` 会自动扩容
|
||||||
|
所以 `Capacity` 往往大于等于 `Count`
|
||||||
|
|
||||||
|
----
|
||||||
|
# 常用成员
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>() { 3, 1, 2, 1 };
|
||||||
|
|
||||||
|
Console.WriteLine(list.Count);
|
||||||
|
Console.WriteLine(list.Contains(2));
|
||||||
|
Console.WriteLine(list.IndexOf(1));
|
||||||
|
Console.WriteLine(list.LastIndexOf(1));
|
||||||
|
|
||||||
|
list.Sort();
|
||||||
|
list.Reverse();
|
||||||
|
```
|
||||||
|
|
||||||
|
常用方法:
|
||||||
|
1. `Add(T item)`:添加一个元素
|
||||||
|
2. `AddRange(IEnumerable<T>)`:添加一组元素
|
||||||
|
3. `Insert(int index, T item)`:插入元素
|
||||||
|
4. `Remove(T item)`:删除第一个匹配项
|
||||||
|
5. `RemoveAt(int index)`:按下标删除
|
||||||
|
6. `Clear()`:清空
|
||||||
|
7. `Contains(T item)`:判断是否存在
|
||||||
|
8. `IndexOf(T item)`:正向查找下标
|
||||||
|
9. `LastIndexOf(T item)`:反向查找下标
|
||||||
|
10. `Sort()`:排序
|
||||||
|
11. `Reverse()`:反转
|
||||||
|
|
||||||
|
----
|
||||||
|
# 排序和反转
|
||||||
|
排序:
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>() { 3, 5, 1, 2 };
|
||||||
|
list.Sort();
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
```text
|
||||||
|
1 2 3 5
|
||||||
|
```
|
||||||
|
|
||||||
|
反转:
|
||||||
|
```csharp
|
||||||
|
list.Reverse();
|
||||||
|
```
|
||||||
|
|
||||||
|
结果:
|
||||||
|
```text
|
||||||
|
5 3 2 1
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
`Sort()` 默认按从小到大排序
|
||||||
|
`Reverse()` 是把当前顺序直接反过来
|
||||||
|
|
||||||
|
----
|
||||||
|
# 插入和删除时要注意下标
|
||||||
|
错误示例:
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>();
|
||||||
|
list.Add(10);
|
||||||
|
|
||||||
|
// list[1] = 20;
|
||||||
|
// list.RemoveAt(5);
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
下标越界会报错
|
||||||
|
|
||||||
|
更稳的写法:
|
||||||
|
```csharp
|
||||||
|
if (list.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine(list[0]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
`List<T>` 虽然长度可变
|
||||||
|
但访问下标时仍然必须合法
|
||||||
|
|
||||||
|
----
|
||||||
|
# 泛型的好处
|
||||||
|
```csharp
|
||||||
|
List<int> numbers = new List<int>();
|
||||||
|
numbers.Add(10);
|
||||||
|
// numbers.Add("hello");
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
`List<int>` 只能存 `int`
|
||||||
|
像 `"hello"` 这种类型不匹配的值,编译阶段就会报错
|
||||||
|
|
||||||
|
优点:
|
||||||
|
1. 类型安全
|
||||||
|
2. 减少强制类型转换
|
||||||
|
3. 代码提示更清楚
|
||||||
|
4. 更适合实际开发
|
||||||
|
|
||||||
|
----
|
||||||
|
# 基础案例:怪物列表
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Monster monster1 = new Boss();
|
||||||
|
Monster monster2 = new Goblin();
|
||||||
|
Monster monster3 = new Boss();
|
||||||
|
Monster monster4 = new Goblin();
|
||||||
|
|
||||||
|
for (int i = 0; i < Monster.Monsters.Count; i++)
|
||||||
|
{
|
||||||
|
Monster.Monsters[i].Atk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Monster
|
||||||
|
{
|
||||||
|
public static List<Monster> Monsters = new List<Monster>();
|
||||||
|
|
||||||
|
public Monster()
|
||||||
|
{
|
||||||
|
Monsters.Add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void Atk();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Boss : Monster
|
||||||
|
{
|
||||||
|
public override void Atk()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Boss Atk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Goblin : Monster
|
||||||
|
{
|
||||||
|
public override void Atk()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Goblin Atk");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
```text
|
||||||
|
Boss Atk
|
||||||
|
Goblin Atk
|
||||||
|
Boss Atk
|
||||||
|
Goblin Atk
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
1. `List<Monster>` 用来统一保存所有怪物对象
|
||||||
|
2. 因为 `Boss` 和 `Goblin` 都继承 `Monster`
|
||||||
|
3. 所以它们都能放进 `List<Monster>` 中
|
||||||
|
4. 再通过遍历统一调用攻击方法
|
||||||
|
|
||||||
|
----
|
||||||
|
# 适合场景
|
||||||
|
1. 玩家背包中的物品列表
|
||||||
|
2. 敌人列表、角色列表、任务列表
|
||||||
|
3. 聊天消息列表
|
||||||
|
4. 成绩列表、订单列表、日志列表
|
||||||
|
|
||||||
|
一句话:
|
||||||
|
只要你需要“数量不固定的一组同类型数据”
|
||||||
|
通常都可以先考虑 `List<T>`
|
||||||
|
|
||||||
|
----
|
||||||
|
# 注意
|
||||||
|
1. `List<T>` 在 `System.Collections.Generic` 命名空间中
|
||||||
|
2. `List<T>` 是泛型集合,`T` 表示元素类型
|
||||||
|
3. `Count` 是实际元素个数,不是容量
|
||||||
|
4. `Capacity` 是当前容量,可能大于 `Count`
|
||||||
|
5. `Add` 是追加到末尾
|
||||||
|
6. `Insert` 是插入到指定位置
|
||||||
|
7. `Remove` 删除的是第一个匹配项
|
||||||
|
8. `RemoveAt` 删除的是指定下标元素
|
||||||
|
9. `List<T>` 很常用,但按下标中间插入/删除很多次时会有移动开销
|
||||||
|
|
||||||
|
----
|
||||||
|
# 易错点
|
||||||
|
1. `List<T>` 是类,不是数组,但用法上和数组有点像
|
||||||
|
2. `Count` 不是 `Length`
|
||||||
|
3. `Capacity` 不是当前元素数量
|
||||||
|
4. `foreach` 遍历时一般不要直接改集合内容
|
||||||
|
5. 下标访问、`Insert`、`RemoveAt` 都要注意越界
|
||||||
|
|
||||||
|
错误示例:
|
||||||
|
```csharp
|
||||||
|
List<int> list = new List<int>() { 10, 20, 30 };
|
||||||
|
|
||||||
|
// Console.WriteLine(list[3]);
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
下标从 `0` 开始
|
||||||
|
上面这个列表只有 `0`、`1`、`2` 三个有效下标
|
||||||
|
|
||||||
|
----
|
||||||
|
# 一句话记忆
|
||||||
|
==List<T> 是长度可变、类型安全、最常用的泛型列表集合。==
|
||||||
|
|
||||||
|
----
|
||||||
|
# 面试/复习时怎么说
|
||||||
|
可以这样答:
|
||||||
|
|
||||||
|
“`List<T>` 是 C# 中非常常用的泛型集合,本质上可以理解成长度可变的数组。
|
||||||
|
它支持按下标访问,也支持方便的增删查改,比如 `Add`、`Insert`、`Remove`、`RemoveAt`。
|
||||||
|
相比 `ArrayList`,`List<T>` 类型更安全,通常不需要强制类型转换,所以在实际开发中更常用。”
|
||||||
|
|
||||||
|
----
|
||||||
|
引用:
|
||||||
|
1. Microsoft Learn: [List<T> Class](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=net-9.0)
|
||||||
|
2. Microsoft Learn: [System.Collections.Generic Namespace](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic?view=net-9.0)
|
||||||
|
|
||||||
|
#List
|
||||||
|
#泛型集合
|
||||||
|
#集合
|
||||||
|
#进阶
|
||||||
@@ -0,0 +1,426 @@
|
|||||||
|
# 泛型约束
|
||||||
|
概念:
|
||||||
|
泛型默认可以接收很多类型
|
||||||
|
如果我们希望 `T` 只能是“某一类类型”,就要加==泛型约束==
|
||||||
|
|
||||||
|
作用:
|
||||||
|
1. 限制泛型参数的取值范围
|
||||||
|
2. 让编译器提前检查类型是否符合要求
|
||||||
|
3. 让我们可以安全地使用某些成员或写法
|
||||||
|
4. 比如 `new T()`、调用接口方法、访问父类成员
|
||||||
|
|
||||||
|
关键字:
|
||||||
|
```csharp
|
||||||
|
where
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 通常用法
|
||||||
|
1. 限制泛型必须是引用类型或值类型
|
||||||
|
2. 限制泛型必须继承某个类
|
||||||
|
3. 限制泛型必须实现某个接口
|
||||||
|
4. 限制泛型必须有无参构造函数
|
||||||
|
5. 在工具类、工厂类、集合封装、通用算法中很常见
|
||||||
|
|
||||||
|
简单理解:
|
||||||
|
泛型像“留空的类型位置”
|
||||||
|
约束就是给这个空位加规则
|
||||||
|
不是任何类型都能随便传进来
|
||||||
|
|
||||||
|
----
|
||||||
|
# 语法
|
||||||
|
类上的泛型约束:
|
||||||
|
```csharp
|
||||||
|
class 类名<T> where T : 约束
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
方法上的泛型约束:
|
||||||
|
```csharp
|
||||||
|
void 方法名<T>() where T : 约束
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
多个泛型参数分别约束:
|
||||||
|
```csharp
|
||||||
|
class Test<T, K>
|
||||||
|
where T : class
|
||||||
|
where K : new()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
多个约束组合写法:
|
||||||
|
```csharp
|
||||||
|
class Test<T> where T : 父类名, 接口名, new()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 常见约束
|
||||||
|
常见的基础约束有 6 种:
|
||||||
|
|
||||||
|
| 约束写法 | 含义 |
|
||||||
|
|---|---|
|
||||||
|
| `where T : struct` | `T` 必须是值类型 |
|
||||||
|
| `where T : class` | `T` 必须是引用类型 |
|
||||||
|
| `where T : new()` | `T` 必须有公共无参构造函数 |
|
||||||
|
| `where T : 类名` | `T` 必须是某个类或它的子类 |
|
||||||
|
| `where T : 接口名` | `T` 必须实现某个接口 |
|
||||||
|
| `where T : U` | `T` 必须是另一个泛型参数 `U` 或它的派生类型 |
|
||||||
|
|
||||||
|
补充:
|
||||||
|
现在 C# 里还会见到一些新约束,比如:
|
||||||
|
`class?`、`notnull`、`unmanaged`、`default`
|
||||||
|
入门和面试里最常见的,还是前面这 6 种
|
||||||
|
|
||||||
|
----
|
||||||
|
# 1. struct 约束
|
||||||
|
作用:
|
||||||
|
要求泛型参数必须是==值类型==
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Test<T> where T : struct
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
正确:
|
||||||
|
```csharp
|
||||||
|
Test<int> t1 = new Test<int>();
|
||||||
|
Test<bool> t2 = new Test<bool>();
|
||||||
|
```
|
||||||
|
|
||||||
|
错误:
|
||||||
|
```csharp
|
||||||
|
// Test<string> t3 = new Test<string>();
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
`int`、`float`、`bool`、`char`、结构体 都属于值类型
|
||||||
|
|
||||||
|
----
|
||||||
|
# 2. class 约束
|
||||||
|
作用:
|
||||||
|
要求泛型参数必须是==引用类型==
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Test<T> where T : class
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
正确:
|
||||||
|
```csharp
|
||||||
|
Test<string> t1 = new Test<string>();
|
||||||
|
Test<object> t2 = new Test<object>();
|
||||||
|
```
|
||||||
|
|
||||||
|
错误:
|
||||||
|
```csharp
|
||||||
|
// Test<int> t3 = new Test<int>();
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
类、数组、字符串、委托等通常都是引用类型
|
||||||
|
|
||||||
|
----
|
||||||
|
# 3. new() 约束
|
||||||
|
作用:
|
||||||
|
要求泛型参数必须有==公共无参构造函数==
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Factory<T> where T : new()
|
||||||
|
{
|
||||||
|
public T Create()
|
||||||
|
{
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
案例:
|
||||||
|
```csharp
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
public Player()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factory<Player> factory = new Factory<Player>();
|
||||||
|
Player p = factory.Create();
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
如果不加 `where T : new()`,就不能直接写 `new T()`
|
||||||
|
|
||||||
|
----
|
||||||
|
# 4. 父类约束
|
||||||
|
作用:
|
||||||
|
要求泛型参数必须是==某个类本身或它的子类==
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Animal
|
||||||
|
{
|
||||||
|
public void Eat()
|
||||||
|
{
|
||||||
|
Console.WriteLine("吃东西");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dog : Animal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test<T> where T : Animal
|
||||||
|
{
|
||||||
|
public void DoSomething(T value)
|
||||||
|
{
|
||||||
|
value.Eat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用:
|
||||||
|
```csharp
|
||||||
|
Test<Animal> t1 = new Test<Animal>();
|
||||||
|
Test<Dog> t2 = new Test<Dog>();
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
因为 `T` 一定是 `Animal` 或其子类
|
||||||
|
所以可以直接把 `T` 当成 `Animal` 来用
|
||||||
|
|
||||||
|
----
|
||||||
|
# 5. 接口约束
|
||||||
|
作用:
|
||||||
|
要求泛型参数必须==实现某个接口==
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
interface IFly
|
||||||
|
{
|
||||||
|
void Fly();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bird : IFly
|
||||||
|
{
|
||||||
|
public void Fly()
|
||||||
|
{
|
||||||
|
Console.WriteLine("飞行");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test<T> where T : IFly
|
||||||
|
{
|
||||||
|
public void StartFly(T value)
|
||||||
|
{
|
||||||
|
value.Fly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
使用:
|
||||||
|
```csharp
|
||||||
|
Test<Bird> t = new Test<Bird>();
|
||||||
|
t.StartFly(new Bird());
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
因为约束保证了 `T` 一定有 `Fly()`
|
||||||
|
所以在泛型里可以直接调用接口成员
|
||||||
|
|
||||||
|
----
|
||||||
|
# 6. 泛型参数之间的约束
|
||||||
|
作用:
|
||||||
|
让一个泛型参数受另一个泛型参数限制
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Test<T, K> where T : K
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
`T : K` 表示 `T` 必须是 `K` 本身
|
||||||
|
或者是 `K` 的派生类型、实现类型
|
||||||
|
|
||||||
|
案例:
|
||||||
|
```csharp
|
||||||
|
class Animal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dog : Animal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Test<Dog, Animal> t = new Test<Dog, Animal>();
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
# 组合约束
|
||||||
|
泛型约束可以组合使用:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
class Test<T> where T : Animal, IFly, new()
|
||||||
|
{
|
||||||
|
public T CreateAndUse()
|
||||||
|
{
|
||||||
|
T value = new T();
|
||||||
|
value.Eat();
|
||||||
|
value.Fly();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
含义:
|
||||||
|
1. `T` 必须继承 `Animal`
|
||||||
|
2. `T` 必须实现 `IFly`
|
||||||
|
3. `T` 必须有公共无参构造函数
|
||||||
|
|
||||||
|
----
|
||||||
|
# 基础案例
|
||||||
|
```csharp
|
||||||
|
using System;
|
||||||
|
|
||||||
|
interface IRun
|
||||||
|
{
|
||||||
|
void Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Player : IRun
|
||||||
|
{
|
||||||
|
public Player()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
Console.WriteLine("玩家正在移动");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Manager<T> where T : IRun, new()
|
||||||
|
{
|
||||||
|
public T Create()
|
||||||
|
{
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(T obj)
|
||||||
|
{
|
||||||
|
obj.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager<Player> manager = new Manager<Player>();
|
||||||
|
Player player = manager.Create();
|
||||||
|
manager.Start(player);
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
```text
|
||||||
|
玩家正在移动
|
||||||
|
```
|
||||||
|
|
||||||
|
理解:
|
||||||
|
因为 `T` 同时满足 `IRun` 和 `new()`
|
||||||
|
所以既能 `new T()`,又能调用 `Run()`
|
||||||
|
|
||||||
|
----
|
||||||
|
# 约束能解决什么问题
|
||||||
|
没有约束时:
|
||||||
|
```csharp
|
||||||
|
class Test<T>
|
||||||
|
{
|
||||||
|
public void Show(T value)
|
||||||
|
{
|
||||||
|
// 这里不能随便调用 value 的成员
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
编译器不知道 `T` 到底是什么类型
|
||||||
|
|
||||||
|
加上约束后:
|
||||||
|
```csharp
|
||||||
|
interface IShow
|
||||||
|
{
|
||||||
|
void Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Test<T> where T : IShow
|
||||||
|
{
|
||||||
|
public void Print(T value)
|
||||||
|
{
|
||||||
|
value.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
约束的本质,就是告诉编译器:
|
||||||
|
“这个泛型参数至少具备这些能力”
|
||||||
|
|
||||||
|
----
|
||||||
|
# 注意
|
||||||
|
1. 泛型约束使用关键字 `where`
|
||||||
|
2. `new()` 约束表示必须有公共无参构造函数
|
||||||
|
3. 想写 `new T()`,必须加 `where T : new()`
|
||||||
|
4. 父类约束和接口约束可以让我们安全调用成员
|
||||||
|
5. 一个泛型参数可以同时有多个约束
|
||||||
|
6. 如果有 `new()`,通常要写在约束列表最后
|
||||||
|
7. `struct` 和 `class` 一般不能同时使用
|
||||||
|
8. 约束的作用是“限制类型 + 提供可用能力”
|
||||||
|
|
||||||
|
----
|
||||||
|
# 易错点
|
||||||
|
1. `new()` 不是“可以 new 一切”,而是“必须存在公共无参构造函数”
|
||||||
|
2. 有参构造函数不算满足 `new()`
|
||||||
|
3. `where T : 类名` 表示继承这个类,不是“名字像这个类”
|
||||||
|
4. `where T : 接口名` 表示实现接口,不是普通包含同名方法
|
||||||
|
5. 没有约束时,不能因为自己“知道”类型就直接调用成员
|
||||||
|
|
||||||
|
错误示例:
|
||||||
|
```csharp
|
||||||
|
class Person
|
||||||
|
{
|
||||||
|
public Person(string name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Factory<Person> factory = new Factory<Person>();
|
||||||
|
```
|
||||||
|
|
||||||
|
原因:
|
||||||
|
`Person` 没有公共无参构造函数
|
||||||
|
所以不满足 `new()`
|
||||||
|
|
||||||
|
----
|
||||||
|
# 一句话记忆
|
||||||
|
==泛型约束就是给泛型参数加条件,让它只能使用满足要求的类型。==
|
||||||
|
|
||||||
|
----
|
||||||
|
# 面试/复习时怎么说
|
||||||
|
可以这样答:
|
||||||
|
|
||||||
|
“泛型约束就是用 `where` 给泛型参数加限制。
|
||||||
|
比如可以限制它必须是值类型、引用类型、某个父类、某个接口,或者必须有无参构造函数。
|
||||||
|
这样做的好处是,编译器能提前帮我们检查类型,同时我们在泛型内部也能更安全地 `new T()` 或调用指定成员。”
|
||||||
|
|
||||||
|
----
|
||||||
|
引用:
|
||||||
|
1. Microsoft Learn: [Constraints on type parameters](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters)
|
||||||
|
2. Microsoft Learn: [where (generic type constraint)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint)
|
||||||
|
|
||||||
|
#泛型约束
|
||||||
|
#泛型
|
||||||
|
#CSharp
|
||||||
|
#进阶
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
## 概念:数据结构
|
||||||
|
数据结构是计算机村粗知足的方式(规则)
|
||||||
|
雷也可以算作为一种数据结构
|
||||||
|
|
||||||
|
简单理解就是人定义的存储数据和表示数据之间关系的规则
|
||||||
|
|
||||||
|
常用的数据结构
|
||||||
|
- 数组、栈、队列、链表、树、图、堆、散列表
|
||||||
|
|
||||||
|
### 线性表
|
||||||
|
线性表是一种数据结构,是由N个具有先沟通呢特性的数据元素的有序序列
|
||||||
|
比如数组、ArraryList、Stack、Queue、链表等
|
||||||
|
|
||||||
|
##### 顺序存储
|
||||||
|
数组、stack、queue、list、arraylist都是顺序存储
|
||||||
|
用一组地址连续的存储单元依次存储线性表的各个元素
|
||||||
|
|
||||||
|
#### 链式存储
|
||||||
|
单向列表、双向列表、循环列表都是链式存储
|
||||||
|
在存储单元中的存储地址不一定连续,但是通过
|
||||||
|
|
||||||
+13
-12
@@ -35,17 +35,18 @@
|
|||||||
3. [[Queue]]
|
3. [[Queue]]
|
||||||
4. [[Hashtable]]
|
4. [[Hashtable]]
|
||||||
5. [[泛型]]和[[泛型约束]]
|
5. [[泛型]]和[[泛型约束]]
|
||||||
6. List
|
6. [[List]]
|
||||||
7. Dictionary
|
7. [[Dictionary]]
|
||||||
8. LinkedList
|
8. 顺序存储和链式存储
|
||||||
9. 泛型栈和队列
|
9. LinkedList
|
||||||
10. 委托事件
|
10. 泛型栈和队列
|
||||||
11. 匿名函数
|
11. 委托事件
|
||||||
12. lambda
|
12. 匿名函数
|
||||||
13. List排序
|
13. lambda
|
||||||
14. 协变逆变
|
14. List排序
|
||||||
15. 多线程
|
15. 协变逆变
|
||||||
16. 预处理器
|
16. 多线程
|
||||||
17. 反射
|
17. 预处理器
|
||||||
|
18. 反射
|
||||||
# 杂记
|
# 杂记
|
||||||
1. [[命名法]]
|
1. [[命名法]]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
当前笔记库路径:
|
当前笔记库路径:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
E:\Obsidian\OneDrive\Apps\remotely-save\MyNotes
|
%USERPROFILE%\OneDrive\Apps\remotely-save\MyNotes
|
||||||
```
|
```
|
||||||
|
|
||||||
GitHub 远程仓库:
|
GitHub 远程仓库:
|
||||||
@@ -22,13 +22,13 @@ https://github.com/Ki5ter/Obsidian.git
|
|||||||
推荐设置成类似:
|
推荐设置成类似:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
E:\GitRepos
|
%USERPROFILE%\GitRepos
|
||||||
```
|
```
|
||||||
|
|
||||||
不推荐设置成:
|
不推荐设置成:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
E:\Obsidian\OneDrive\Apps\remotely-save\MyNotes
|
%USERPROFILE%\OneDrive\Apps\remotely-save\MyNotes
|
||||||
```
|
```
|
||||||
|
|
||||||
原因是 `MyNotes` 本身就是一个仓库,不应该再作为所有新仓库的默认存放目录。
|
原因是 `MyNotes` 本身就是一个仓库,不应该再作为所有新仓库的默认存放目录。
|
||||||
@@ -52,7 +52,7 @@ URL: https://github.com/Ki5ter/Obsidian.git
|
|||||||
1. 在资源管理器中找到笔记库文件夹:
|
1. 在资源管理器中找到笔记库文件夹:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
E:\Obsidian\OneDrive\Apps\remotely-save\MyNotes
|
%USERPROFILE%\OneDrive\Apps\remotely-save\MyNotes
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 如果笔记库在 OneDrive 里,先右键文件夹,选择:
|
2. 如果笔记库在 OneDrive 里,先右键文件夹,选择:
|
||||||
@@ -125,6 +125,24 @@ git -C "E:\Obsidian\OneDrive\Apps\remotely-save\MyNotes" branch -M main
|
|||||||
git -C "E:\Obsidian\OneDrive\Apps\remotely-save\MyNotes" push -u origin main
|
git -C "E:\Obsidian\OneDrive\Apps\remotely-save\MyNotes" push -u origin main
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 不建议提交 .vs 目录
|
||||||
|
|
||||||
|
Visual Studio 会在仓库里生成 `.vs/` 目录,用来保存本机缓存、索引、窗口布局等内容。
|
||||||
|
|
||||||
|
这些文件通常只和当前电脑有关,不适合推送到 GitHub。建议在 `.gitignore` 中加入:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
/.vs/
|
||||||
|
```
|
||||||
|
|
||||||
|
如果 `.vs/` 已经被 Git 跟踪过,需要取消跟踪但保留本地文件:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git rm --cached -r -- ".vs"
|
||||||
|
git commit -m "Stop tracking Visual Studio local files"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
## Clash Verge 代理问题
|
## Clash Verge 代理问题
|
||||||
|
|
||||||
如果推送时报错:
|
如果推送时报错:
|
||||||
|
|||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
# Git 命令速查
|
||||||
|
|
||||||
|
## 初始化和远端
|
||||||
|
|
||||||
|
初始化本地仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git init
|
||||||
|
```
|
||||||
|
|
||||||
|
添加远端仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote add origin https://github.com/Ki5ter/Obsidian.git
|
||||||
|
```
|
||||||
|
|
||||||
|
查看远端仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote -v
|
||||||
|
```
|
||||||
|
|
||||||
|
`origin` 是本地给远端仓库地址起的别名,也可以叫 `backup`、`gitee` 等。
|
||||||
|
|
||||||
|
## 日常提交
|
||||||
|
|
||||||
|
查看状态:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git status
|
||||||
|
git status --short
|
||||||
|
```
|
||||||
|
|
||||||
|
加入暂存区:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add .
|
||||||
|
```
|
||||||
|
|
||||||
|
提交到本地仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git commit -m "提交说明"
|
||||||
|
```
|
||||||
|
|
||||||
|
第一次推送并绑定上游:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push -u origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
绑定后日常推送:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
## 分支和上游
|
||||||
|
|
||||||
|
查看当前分支和上游关系:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git branch -vv
|
||||||
|
```
|
||||||
|
|
||||||
|
`master` 或 `main` 是分支名。`git push origin master` 表示把本地 `master` 分支推送到 `origin` 这个远端。
|
||||||
|
|
||||||
|
`-u` 会把本地分支和远端分支绑定起来。绑定后,Git 知道当前分支默认推送到哪里。
|
||||||
|
|
||||||
|
## .gitignore 和取消跟踪
|
||||||
|
|
||||||
|
`.gitignore` 只会阻止未被跟踪的新文件进入 Git。已经被 Git 跟踪的文件,需要先从索引中移除。
|
||||||
|
|
||||||
|
只取消 Git 跟踪,保留本地文件:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git rm --cached -r -- "目录或文件名"
|
||||||
|
git commit -m "Stop tracking local-only files"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
`--cached` 指 Git 索引/暂存区,不是普通缓存。它不会删除本地实际文件。
|
||||||
|
|
||||||
|
## 清理历史中的敏感文件
|
||||||
|
|
||||||
|
如果密码、密钥、Token 已经提交过,只从最新提交删除还不够,历史里仍然能看到。应先更换或吊销泄露过的密钥,再重写历史。
|
||||||
|
|
||||||
|
删除整个历史中的指定目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --path "密码本/" --path "服务器迁移/" --invert-paths
|
||||||
|
```
|
||||||
|
|
||||||
|
如果不是 fresh clone,工具可能要求确认:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --force --path "密码本/" --path "服务器迁移/" --invert-paths
|
||||||
|
```
|
||||||
|
|
||||||
|
`--path` 指定要匹配的路径;`--invert-paths` 表示反转选择,保留其他路径,删除这些指定路径。
|
||||||
|
|
||||||
|
`git filter-repo` 执行后可能会删除 `origin`,需要重新添加:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote add origin https://github.com/Ki5ter/Obsidian.git
|
||||||
|
```
|
||||||
|
|
||||||
|
历史重写后强推远端:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git fetch origin
|
||||||
|
git push --force-with-lease origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
`--force-with-lease` 会先确认远端分支还停在本地记录的位置,避免覆盖别人新推送的提交。
|
||||||
|
|
||||||
|
检查历史里是否还存在指定目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git log --all -- "密码本/" "服务器迁移/"
|
||||||
|
```
|
||||||
+112
@@ -42,6 +42,9 @@ https://github.com/Ki5ter/Obsidian.git
|
|||||||
`fetch 获取`:
|
`fetch 获取`:
|
||||||
只下载远程仓库信息,不自动合并。
|
只下载远程仓库信息,不自动合并。
|
||||||
|
|
||||||
|
`origin/master`:
|
||||||
|
本地记录的远端 `origin` 上 `master` 分支的位置。它不是远端本身,而是本地上次获取到的远端状态。
|
||||||
|
|
||||||
## 基本工作流程
|
## 基本工作流程
|
||||||
|
|
||||||
1. 打开工作区,也就是要纳入版本控制的文件夹。
|
1. 打开工作区,也就是要纳入版本控制的文件夹。
|
||||||
@@ -94,6 +97,36 @@ git push
|
|||||||
git pull
|
git pull
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## origin、master 和 push
|
||||||
|
|
||||||
|
`origin` 是远端仓库地址的别名。它保存在本地 Git 配置里,不是 GitHub 天生的名字。
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote add origin https://github.com/Ki5ter/Obsidian.git
|
||||||
|
```
|
||||||
|
|
||||||
|
如果需要推送到多个远端,可以添加多个别名:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote add backup https://example.com/backup.git
|
||||||
|
```
|
||||||
|
|
||||||
|
`master` 是分支名,也可以叫 `main`、`dev`、`notes`。分支可以理解为一个指向最新提交的指针。
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
这条命令表示把本地 `master` 分支推送到 `origin` 远端。它不会自动推送其他本地分支。
|
||||||
|
|
||||||
|
第一次推送时常用:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push -u origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
`-u` 会设置上游关系。之后在本地 `master` 分支上执行 `git push` 或 `git pull`,Git 会自动使用 `origin/master`。
|
||||||
|
|
||||||
## 常用检查命令
|
## 常用检查命令
|
||||||
|
|
||||||
查看当前仓库状态:
|
查看当前仓库状态:
|
||||||
@@ -126,6 +159,73 @@ git remote -v
|
|||||||
git log --oneline --decorate -5
|
git log --oneline --decorate -5
|
||||||
```
|
```
|
||||||
|
|
||||||
|
查看某个路径是否被 ignore 命中:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git check-ignore -v --no-index -- "密码本/任意测试文件.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
查看某个路径是否还被 Git 跟踪:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git ls-files -- "密码本" "服务器迁移"
|
||||||
|
```
|
||||||
|
|
||||||
|
## .gitignore 的作用
|
||||||
|
|
||||||
|
`.gitignore` 用来告诉 Git:哪些未被跟踪的新文件不要加入版本控制。
|
||||||
|
|
||||||
|
推荐把只在仓库根目录生效的目录写成:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
/密码本/
|
||||||
|
/服务器迁移/
|
||||||
|
```
|
||||||
|
|
||||||
|
开头的 `/` 表示仓库根目录,结尾的 `/` 表示目录。
|
||||||
|
|
||||||
|
如果只写:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
密码本
|
||||||
|
```
|
||||||
|
|
||||||
|
也能生效,但它会匹配仓库中任何位置名为 `密码本` 的文件或目录,不如 `/密码本/` 精确。
|
||||||
|
|
||||||
|
已经被 Git 跟踪过的文件不会因为加入 `.gitignore` 自动消失。需要执行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git rm --cached -r -- "目录或文件名"
|
||||||
|
```
|
||||||
|
|
||||||
|
这会从 Git 跟踪列表中移除文件,但保留本地实际文件。
|
||||||
|
|
||||||
|
## 清理历史中的敏感内容
|
||||||
|
|
||||||
|
如果敏感文件已经推送到远程仓库,只在最新提交中删除还不够,旧提交里仍然可能看到。
|
||||||
|
|
||||||
|
清理历史的思路是:重写本地提交历史,让每个相关提交都不再包含敏感路径,然后强制替换远端分支。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --path "密码本/" --path "服务器迁移/" --invert-paths
|
||||||
|
git fetch origin
|
||||||
|
git push --force-with-lease origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
`git filter-repo` 不是 Git 自带命令,需要单独安装。`--invert-paths` 表示反转路径选择:保留其他所有路径,移除 `--path` 指定的路径。
|
||||||
|
|
||||||
|
普通 `git push` 只允许向前追加提交。重写历史后,本地提交 ID 已经变化,远端会拒绝普通 push,因此需要:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push --force-with-lease origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
`--force-with-lease` 比 `--force` 更安全。它会检查远端分支是否仍停在本地记录的位置;如果别人已经推送了新提交,它会拒绝覆盖。
|
||||||
|
|
||||||
|
敏感信息如果已经泄露过,清理 Git 历史只是补救之一。密码、Recovery Key、Token 等应视为已经泄露,优先更换或吊销。
|
||||||
|
|
||||||
## Obsidian 笔记库使用 Git 的注意事项
|
## Obsidian 笔记库使用 Git 的注意事项
|
||||||
|
|
||||||
Obsidian 笔记库适合用 Git 备份,因为大多数内容都是 Markdown 文本文件。
|
Obsidian 笔记库适合用 Git 备份,因为大多数内容都是 Markdown 文本文件。
|
||||||
@@ -148,6 +248,18 @@ Obsidian 笔记库适合用 Git 备份,因为大多数内容都是 Markdown
|
|||||||
特别大的二进制文件
|
特别大的二进制文件
|
||||||
```
|
```
|
||||||
|
|
||||||
|
建议忽略:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
/.obsidian/workspace*.json
|
||||||
|
/.obsidian/cache/
|
||||||
|
/.vs/
|
||||||
|
/密码本/
|
||||||
|
/服务器迁移/
|
||||||
|
```
|
||||||
|
|
||||||
|
`workspace*.json` 是 Obsidian 的窗口和布局状态,通常和具体电脑有关。`.vs/` 是 Visual Studio 本地缓存,也不适合提交。
|
||||||
|
|
||||||
如果笔记库在 OneDrive 里,要注意 `.git` 目录必须真实保留在本机。否则 Git 或 Visual Studio 可能会报错,例如:
|
如果笔记库在 OneDrive 里,要注意 `.git` 目录必须真实保留在本机。否则 Git 或 Visual Studio 可能会报错,例如:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
@@ -0,0 +1,269 @@
|
|||||||
|
# 清理 Git 历史中的本地目录模板
|
||||||
|
|
||||||
|
这份模板用于把某个已经推送过的本地目录,从远端仓库的历史提交中移除。
|
||||||
|
|
||||||
|
适用场景:
|
||||||
|
|
||||||
|
```text
|
||||||
|
某个目录已经被 push 到远端
|
||||||
|
后来发现它不适合公开,例如简历、密码本、密钥、隐私资料
|
||||||
|
希望远端最新版本和历史提交中都不再包含它
|
||||||
|
但本地仍然要保留这个目录
|
||||||
|
```
|
||||||
|
|
||||||
|
## 参数
|
||||||
|
|
||||||
|
把下面这些参数替换成自己的实际值:
|
||||||
|
|
||||||
|
```text
|
||||||
|
<原仓库路径> 当前正在使用的本地仓库路径
|
||||||
|
<旧仓库备份路径> 原仓库的备份路径
|
||||||
|
<清理仓库路径> 新 clone 出来的临时清理仓库路径
|
||||||
|
<远端地址> GitHub/Gitee 等远端仓库地址
|
||||||
|
<分支名> 要重写并推送的分支,例如 master 或 main
|
||||||
|
<目录路径> 要从历史中移除的目录,例如 简历/
|
||||||
|
```
|
||||||
|
|
||||||
|
多个目录可以写多个 `--path`:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --path "<目录1>/" --path "<目录2>/" --invert-paths
|
||||||
|
```
|
||||||
|
|
||||||
|
## 重要提醒
|
||||||
|
|
||||||
|
如果目录里包含密码、Recovery Key、Token 等敏感信息,应先更换或吊销这些信息。
|
||||||
|
|
||||||
|
清理 Git 历史只能减少仓库历史中的暴露,不等于保证已经泄露的信息重新安全。
|
||||||
|
|
||||||
|
重写历史后,提交 ID 会变化,因此远端需要强推:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push --force-with-lease origin <分支名>
|
||||||
|
```
|
||||||
|
|
||||||
|
`--force-with-lease` 比 `--force` 更安全。它会先检查远端分支是否仍停在本地记录的位置,避免覆盖别人新推送的提交。
|
||||||
|
|
||||||
|
## 流程
|
||||||
|
|
||||||
|
### 1. 检查原仓库状态
|
||||||
|
|
||||||
|
进入当前本地仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd "<原仓库路径>"
|
||||||
|
git status
|
||||||
|
```
|
||||||
|
|
||||||
|
如果有未提交修改,先提交、备份或手动处理。不要在状态混乱时重写历史。
|
||||||
|
|
||||||
|
### 2. 备份原仓库
|
||||||
|
|
||||||
|
把当前仓库复制或改名保留:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd "<原仓库的上级目录>"
|
||||||
|
ren "<原仓库文件夹名>" "<旧仓库备份文件夹名>"
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以用资源管理器手动复制一份。
|
||||||
|
|
||||||
|
重点是保留本地私有目录,后面要从 old 里复制回新仓库。
|
||||||
|
|
||||||
|
### 3. 在非同步目录重新 clone
|
||||||
|
|
||||||
|
建议不要在 OneDrive、网盘同步目录里执行历史重写。
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd "<临时工作目录>"
|
||||||
|
git clone <远端地址> "<清理仓库文件夹名>"
|
||||||
|
cd "<清理仓库路径>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 清理历史
|
||||||
|
|
||||||
|
清理单个目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --path "<目录路径>/" --invert-paths
|
||||||
|
```
|
||||||
|
|
||||||
|
清理多个目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --path "<目录1>/" --path "<目录2>/" --invert-paths
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
```text
|
||||||
|
--path 指定要匹配的路径
|
||||||
|
--invert-paths 反转选择,保留其他路径,移除指定路径
|
||||||
|
```
|
||||||
|
|
||||||
|
如果提示不是 fresh clone,可以在确认备份无误后使用:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git filter-repo --force --path "<目录路径>/" --invert-paths
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 检查并恢复 remote
|
||||||
|
|
||||||
|
`git filter-repo` 可能会删除 `origin` remote。
|
||||||
|
|
||||||
|
检查:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote -v
|
||||||
|
```
|
||||||
|
|
||||||
|
如果没有输出,重新添加:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git remote add origin <远端地址>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 修改 .gitignore
|
||||||
|
|
||||||
|
把本地要保留、但以后不再提交的目录写入 `.gitignore`:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
/<目录路径>/
|
||||||
|
```
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
```gitignore
|
||||||
|
/简历/
|
||||||
|
```
|
||||||
|
|
||||||
|
提交 `.gitignore` 修改:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add .gitignore
|
||||||
|
git commit -m "Ignore local-only directory"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. 获取远端状态
|
||||||
|
|
||||||
|
执行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git fetch origin
|
||||||
|
```
|
||||||
|
|
||||||
|
`fetch` 不是合并。它只是把远端当前状态下载到本地,例如更新 `origin/<分支名>`。
|
||||||
|
|
||||||
|
这里的作用是让 `--force-with-lease` 能检查远端分支是否被别人更新过。
|
||||||
|
|
||||||
|
### 8. 强推清理后的历史
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git push --force-with-lease origin <分支名>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果成功,远端 `<分支名>` 会被替换成清理后的新历史。
|
||||||
|
|
||||||
|
### 9. 检查清理结果
|
||||||
|
|
||||||
|
检查历史中是否还存在目标目录:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git log --all -- "<目录路径>/"
|
||||||
|
```
|
||||||
|
|
||||||
|
没有输出,说明当前可见历史里已经找不到这个目录。
|
||||||
|
|
||||||
|
也可以检查远端分支:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git fetch origin
|
||||||
|
git log origin/<分支名> -- "<目录路径>/"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. 重建日常使用的本地仓库
|
||||||
|
|
||||||
|
回到原来的仓库位置,从远端重新 clone:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd "<原仓库的上级目录>"
|
||||||
|
git clone <远端地址> "<原仓库文件夹名>"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11. 复制回本地私有目录
|
||||||
|
|
||||||
|
从 old 备份中,把本地要保留但不提交的目录复制回新仓库:
|
||||||
|
|
||||||
|
```text
|
||||||
|
<旧仓库备份路径>/<目录路径>
|
||||||
|
复制到
|
||||||
|
<原仓库路径>/<目录路径>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12. 最终验证
|
||||||
|
|
||||||
|
进入新仓库:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd "<原仓库路径>"
|
||||||
|
git status
|
||||||
|
git check-ignore -v --no-index -- "<目录路径>/任意测试文件.md"
|
||||||
|
git log --all -- "<目录路径>/"
|
||||||
|
```
|
||||||
|
|
||||||
|
理想结果:
|
||||||
|
|
||||||
|
```text
|
||||||
|
git status 没有异常改动
|
||||||
|
git check-ignore 能看到 .gitignore 命中规则
|
||||||
|
git log 没有输出
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### filter-repo 不是 Git 命令
|
||||||
|
|
||||||
|
报错:
|
||||||
|
|
||||||
|
```text
|
||||||
|
git: 'filter-repo' is not a git command
|
||||||
|
```
|
||||||
|
|
||||||
|
说明还没有安装 `git-filter-repo`。
|
||||||
|
|
||||||
|
可以尝试:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m pip install git-filter-repo
|
||||||
|
```
|
||||||
|
|
||||||
|
### push 被拒绝 stale info
|
||||||
|
|
||||||
|
如果强推时报:
|
||||||
|
|
||||||
|
```text
|
||||||
|
! [rejected] <分支名> -> <分支名> (stale info)
|
||||||
|
```
|
||||||
|
|
||||||
|
通常是因为本地没有最新的 `origin/<分支名>` 信息。
|
||||||
|
|
||||||
|
先执行:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git fetch origin
|
||||||
|
git push --force-with-lease origin <分支名>
|
||||||
|
```
|
||||||
|
|
||||||
|
### .gitignore 不会影响已跟踪文件
|
||||||
|
|
||||||
|
`.gitignore` 只影响未被跟踪的新文件。
|
||||||
|
|
||||||
|
如果某个文件已经被 Git 跟踪,需要取消跟踪:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git rm --cached -r -- "<目录路径>"
|
||||||
|
git commit -m "Stop tracking local-only directory"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
这只会从 Git 跟踪列表中移除,不会删除本地实际文件。
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# !\[不完整指令]
|
||||||
|
|
||||||
|
作用:执行最近一次的指令
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- !py
|
||||||
|
- !exec
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
作用:查看历史输入过的命令
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
同yum
|
||||||
|
但apt把yum的update拆成了两步
|
||||||
|
1.`apt update`:**仅仅是刷新软件源列表**(类似于刷新网购商品的降价清单,不下载任何具体软件)。
|
||||||
|
2.`apt upgrade`:**这步才是真正的下载并更新软件**。
|
||||||
|
|
||||||
|
安装包:
|
||||||
|
- .deb
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# cat \[文件]
|
||||||
|
|
||||||
|
作用:查看文件
|
||||||
|
|
||||||
|
示例:
|
||||||
|
cat ./test.txt
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# chmod \[-R] \[权限] \[文件或文件夹]
|
||||||
|
|
||||||
|
作用:修改文件/文件夹本身的权限
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- r:对文件夹及以内的所有内容做同样的操作
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- chmod u=rwx,g=rx,o=x hello.txt
|
||||||
|
- chmod -R u=rwx,g=rx,o=x test
|
||||||
|
|
||||||
|
|
||||||
|
权限还能用数字来表示
|
||||||
|
特殊写法:
|
||||||
|
- `r=4`
|
||||||
|
- `w=2`
|
||||||
|
- `x=1`
|
||||||
|
- 所以 `rwx=7`,`rw-=6`,`r-x=5`。
|
||||||
|
示例:
|
||||||
|
- chmod 755 hello.sh
|
||||||
|
- chmod 644 text.txt
|
||||||
|
- chmod -R 755 test
|
||||||
|
|
||||||
|
# choown \[-R] \[用户] \[:] \[用户组] \[文件或文件夹]
|
||||||
|
|
||||||
|
作用:修改文件或文件夹的所属用户或用户组
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- R:同chmod
|
||||||
|
- ::分隔用户何用户组
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- chown kister test.txt //只修改用户
|
||||||
|
- chown :kister test.txt //只修改用户组
|
||||||
|
- chown root:kister test.txt //都改
|
||||||
|
- chown -R root test.txt //递归修改
|
||||||
|
|
||||||
|
注意:
|
||||||
|
- 不能直接把用户或用户组改到其他用户身上,一般都是root执行
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# cp \[-r] \[路径1] \[路径2]
|
|
||||||
|
|
||||||
作用:复制文件/文件夹
|
|
||||||
|
|
||||||
选项:
|
|
||||||
- r 用于复制文件夹使用,表示递归
|
|
||||||
- 路径1表示被复制的文件/文件夹的路径
|
|
||||||
- 路径2表示复制到的文件/文件夹的路径
|
|
||||||
|
|
||||||
示例:
|
|
||||||
- cp ./test1 ./test2
|
|
||||||
- cp -r ./test1/t1 ./test2
|
|
||||||
|
|
||||||
# mv \[参数1] \[参数2]
|
|
||||||
|
|
||||||
作用:移动文件/文件夹,也可以用于改名
|
|
||||||
|
|
||||||
选项:
|
|
||||||
- 参数1表示被移动的文件/文件夹
|
|
||||||
- 参数2表示移动后的文件/文件夹
|
|
||||||
|
|
||||||
示例:
|
|
||||||
- mv ./test1/t1 ./test2
|
|
||||||
- mv ./test1 ./test2
|
|
||||||
# rm \[-r -f -l] \[参数1] \[参数2]...
|
|
||||||
|
|
||||||
作用:删除文件/文件夹
|
|
||||||
|
|
||||||
选项:
|
|
||||||
- -r:和cp一样用于删除文件夹
|
|
||||||
- -f:强制删除
|
|
||||||
- 参数n:多个文件/文件夹
|
|
||||||
|
|
||||||
示例:
|
|
||||||
- rm -r ./test1
|
|
||||||
- rm -f ./test1/t1
|
|
||||||
- rm -rf /test*
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# cp \[-r] \[路径1] \[路径2]
|
||||||
|
|
||||||
|
作用:复制文件/文件夹
|
||||||
|
|
||||||
|
选项:
|
||||||
|
- r 用于复制文件夹使用,表示递归
|
||||||
|
- 路径1表示被复制的文件/文件夹的路径
|
||||||
|
- 路径2表示复制到的文件/文件夹的路径
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- cp ./test1 ./test2
|
||||||
|
- cp -r ./test1/t1 ./test2
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# curl \[-O] \[url]
|
||||||
|
|
||||||
|
作用:发起网络请求
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -O:
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- curl cip.cc
|
||||||
|
- curl baidu.com
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# date \[d] \[格式化字符串]
|
||||||
|
|
||||||
|
作用:按照给定的字符串显示日期,一般用于日期计算
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- 格式化字符串:
|
||||||
|
- %Y年(1999,2026)
|
||||||
|
- %y年份后两位数字(00,99)
|
||||||
|
- %M月份(01,12)
|
||||||
|
- %d日(01,31)
|
||||||
|
- %H小时(00,23)
|
||||||
|
- %M分钟(00,59)
|
||||||
|
- %S秒(00,60)
|
||||||
|
- %s自1970-01-01 00:00:00 UTC到现在的秒数
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- date
|
||||||
|
- date +%Y-%m-%d
|
||||||
|
- date "+%Y-%m-%d %H:%M:%S"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# df \[-h]
|
||||||
|
|
||||||
|
作用:查看磁盘使用情况
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -h:以更人性化的单位进行显示
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- df -h
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# echo 输出的内容
|
||||||
|
|
||||||
|
作用:在命令行输出指定的内容
|
||||||
|
|
||||||
|
选项:无选项
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- echo "\\"Hello Linux\\""
|
||||||
|
- echo \`pwd\`
|
||||||
|
|
||||||
|
# tail \[-f -num] \[路径]
|
||||||
|
|
||||||
|
作用:查看文件尾部内容,追踪文件的最新更改
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -f:表示持续跟踪
|
||||||
|
- -num:表示查看尾部多少行
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- tail -5 test.txt
|
||||||
|
- tail -f test.txt
|
||||||
|
|
||||||
|
# head&less
|
||||||
|
示例:
|
||||||
|
- less log.txt
|
||||||
|
- head -10 log.txt
|
||||||
|
- tail -20 log.txt
|
||||||
|
- tail -f log.txt
|
||||||
|
|
||||||
|
|
||||||
@@ -1,22 +1,11 @@
|
|||||||
|
# find \[起始路径] \[-name -size] \[-type] \[参数] \[+ - n kMG]
|
||||||
这些指令都是程序,所以执行的命令的程序也需要存放
|
|
||||||
|
|
||||||
# which \[参数]
|
|
||||||
|
|
||||||
参数:命令
|
|
||||||
|
|
||||||
作用:查询指令程序的地址
|
|
||||||
|
|
||||||
示例:
|
|
||||||
- whcih pwd
|
|
||||||
|
|
||||||
# find \[起始路径] \[-name -size] \[参数] \[+ - n kMG]
|
|
||||||
|
|
||||||
作用:查找指定文件
|
作用:查找指定文件
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
- -name:直接找符合的文件名
|
- -name:直接找符合的文件名
|
||||||
- -size:查找符合的大小
|
- -size:查找符合的大小
|
||||||
|
- -type:表示查找的类型
|
||||||
- +、-:表示大于或小于
|
- +、-:表示大于或小于
|
||||||
- n:表示大小数字
|
- n:表示大小数字
|
||||||
- kMG:k表示kb(小写),M表示MB,G表示GB
|
- kMG:k表示kb(小写),M表示MB,G表示GB
|
||||||
@@ -25,3 +14,6 @@
|
|||||||
- find / -name "test"
|
- find / -name "test"
|
||||||
- find / -size -10k
|
- find / -size -10k
|
||||||
- find / -size +1G
|
- find / -size +1G
|
||||||
|
- find /home -name "*.txt"
|
||||||
|
- find /home -type f -name "*.log"
|
||||||
|
- find /home -type d -name "test"
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# getent passwd
|
||||||
|
|
||||||
|
作用:查看有哪些用户
|
||||||
|
|
||||||
|
共有7份信息:
|
||||||
|
用户名:密码(X):用户ID:组ID:描述信息:HOME目录:执行终端(默认bash)
|
||||||
|
|
||||||
|
# getent group
|
||||||
|
|
||||||
|
作用:查看有哪些用户组
|
||||||
|
|
||||||
|
共有3份信息:
|
||||||
|
组名:组认证(显示为X):组ID
|
||||||
|
|
||||||
|
# getent hosts \[域名]
|
||||||
|
|
||||||
|
作用:查看本机的DNS解析配置,会同时检查 `/etc/hosts` 文件和 DNS 服务器)
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# grep \[-n -i -v -r] \[关键字] \[内容输入]
|
||||||
|
|
||||||
|
作用:从文件中通过关键字过滤文件行
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -n:可选 表示在结果中显示匹配的行号
|
||||||
|
- -i:可选 忽略大小写
|
||||||
|
- -v: 反向过滤,输出不包含关键字
|
||||||
|
- -r:递归搜索目录
|
||||||
|
- 关键字:必填 表示过滤的关键字,带有空格或其他特殊符号用`""包裹起来
|
||||||
|
- 内容输入:必填 表示要过滤内容的文件路径
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- grep -n "kister" ~/test.txt
|
||||||
|
- grep "kister" ~/test.txt
|
||||||
|
- cat log.txt | grep -i "error" | wc -l
|
||||||
|
|
||||||
|
# wc \[-c -m -l -w] \[内容输入]
|
||||||
|
|
||||||
|
作用:统计文件的行数、单词量等
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -c:统计bytes数量
|
||||||
|
- -m:统计字符数量
|
||||||
|
- -l:统计行数
|
||||||
|
- -w:统计单词数量
|
||||||
|
- 内容输入:必填 表示要统计内容的文件路径
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- wc test.txt
|
||||||
|
- wc -lw test.txt
|
||||||
|
|
||||||
|
# 管道符
|
||||||
|
|
||||||
|
符号:`|
|
||||||
|
|
||||||
|
作用:将左边命令的结果作为右边命令的输入
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- cat text.txt | grep "kister"
|
||||||
|
- ls -la / | grep "home"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
执行条件:root权限
|
||||||
|
|
||||||
|
groupadd \[用户组名]
|
||||||
|
|
||||||
|
groupdel \[用户组名]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
作用:查看用户属于哪些组
|
||||||
|
|
||||||
|
示例:gourps kister
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# hostname
|
||||||
|
作用:查看主机名
|
||||||
|
|
||||||
|
# hostnamectl set-hostname \[主机名]
|
||||||
|
作用:更改主机名
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# iostat \[-x] \[num1] \[num2]
|
||||||
|
|
||||||
|
作用:查看CPU、磁盘等相关信息
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- x:显示更多信息
|
||||||
|
- num1:刷新间隔
|
||||||
|
- num2:刷新次数
|
||||||
|
|
||||||
|
示例:
|
||||||
|
-
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# kill \[-9] \[PID]
|
||||||
|
|
||||||
|
作用:关闭进程
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- 9:强制关闭,不加的时候是发送关闭请求,让进程自己处理
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- kill -9 2339
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# ln -s \[参数1] \[参数2]
|
||||||
|
|
||||||
|
作用:将文件、文件夹链接到其他位置,类似快捷方式
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- s:创建软连接
|
||||||
|
- 参数1:被联军的文件或文件夹
|
||||||
|
- 参数2:要连接去的目的地
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- ln -s /etc/yum.conf ~/yum.conf
|
||||||
|
- ln -s /etc/yum ~/yum
|
||||||
+3
-1
@@ -1,10 +1,12 @@
|
|||||||
# ls \[ -a -l -h] \[路径]
|
# ls \[ -a -l -h -i -r] \[路径]
|
||||||
|
|
||||||
作用:以平铺形式,列出当前工作目录下的内容
|
作用:以平铺形式,列出当前工作目录下的内容
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
|
- i表示删除前询问,可以习惯性的加
|
||||||
- a 表示列出全部内容,包括.开头的隐藏文件
|
- a 表示列出全部内容,包括.开头的隐藏文件
|
||||||
- l 表示垂直列出,给出了权限,用户和用户组等
|
- l 表示垂直列出,给出了权限,用户和用户组等
|
||||||
- h 表示以易于阅读的形式给出文件大小参数,通常和-l配合使用
|
- h 表示以易于阅读的形式给出文件大小参数,通常和-l配合使用
|
||||||
|
- r 表示递归搜索,可以搜索所有子目录
|
||||||
|
|
||||||
输出内容过多时,可以使用 `| less`来减少一次输出的内容量
|
输出内容过多时,可以使用 `| less`来减少一次输出的内容量
|
||||||
@@ -1,17 +1,3 @@
|
|||||||
# touch \[路径]
|
|
||||||
|
|
||||||
作用:创建文件
|
|
||||||
|
|
||||||
示例:
|
|
||||||
touch test.txt
|
|
||||||
|
|
||||||
# cat \[文件]
|
|
||||||
|
|
||||||
作用:查看文件
|
|
||||||
|
|
||||||
示例:
|
|
||||||
cat ./test.txt
|
|
||||||
|
|
||||||
# more \[文件]
|
# more \[文件]
|
||||||
|
|
||||||
作用:查看文件
|
作用:查看文件
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# mv \[参数1] \[参数2]
|
||||||
|
|
||||||
|
作用:移动文件/文件夹,也可以用于改名
|
||||||
|
|
||||||
|
选项:
|
||||||
|
- 参数1表示被移动的文件/文件夹
|
||||||
|
- 参数2表示移动后的文件/文件夹
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- mv ./test1/t1 ./test2
|
||||||
|
- mv ./test1 ./test2
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# netstat \[-anp] \[| grep 端口号]
|
||||||
|
|
||||||
|
**略过时,推荐使用ss(同参数)**
|
||||||
|
|
||||||
|
作用:查看端口的占用情况
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- a:所有端口
|
||||||
|
- n:以数字显示
|
||||||
|
- p:显示进程PID和名称
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- netstat -anp | grep 80
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# nmap \[ip/域名]
|
||||||
|
|
||||||
|
作用:嗅探IP上有哪些端口
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# ntpdate \[u] \[地址]
|
||||||
|
|
||||||
|
作用:设置ntp服务
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- u:指定ntp服务器
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- ntpdate -u ntp.aliyun.com
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
作用:修改用户密码
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- passwd kister
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# ping \[-c num] \[ip]
|
||||||
|
|
||||||
|
作用:查看连通性
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- c:检查的次数(不指定就一直ping
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# ps \[-e -f]
|
||||||
|
|
||||||
|
作用:显示进程
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- e:显示全部进程
|
||||||
|
- f:以格式化方式显示
|
||||||
|
|
||||||
|
输出格式:
|
||||||
|
- UID:进程所属的用户ID
|
||||||
|
- PID:进程号
|
||||||
|
- PPID:进程的父ID(启动次进程的其他进程
|
||||||
|
- C:此进程的CPU占用率
|
||||||
|
- STIME:进程的启动时间
|
||||||
|
- TTY启动此进程的终端序号,如显示?则标识非终端启动
|
||||||
|
- TIME:进程占用CPU的时间
|
||||||
|
- CMD: 进程对应的名称或启动路径或启动命令
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- ps -ef
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# rm \[-r -f -l] \[参数1] \[参数2]...
|
||||||
|
|
||||||
|
作用:删除文件/文件夹
|
||||||
|
|
||||||
|
选项:
|
||||||
|
- -r:和cp一样用于删除文件夹
|
||||||
|
- -f:强制删除
|
||||||
|
- 参数n:多个文件/文件夹
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- rm -r ./test1
|
||||||
|
- rm -f ./test1/t1
|
||||||
|
- rm -rf /test*
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# sar \[-n] DEV \[num1] \[num2]
|
||||||
|
|
||||||
|
作用:查看网络相关统计信息
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -n:查看网络
|
||||||
|
- DEV表示查看的网络接口
|
||||||
|
- num1:刷新间隔/不填只显示一次
|
||||||
|
- num2:查看次数/不填无限次
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- sar -n DEV 3 2
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
语法:su \[用户名] \[-]
|
||||||
|
可以通过exit返回上一个用户或快捷键Ctrl+D
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -:切换后加载环境变量
|
||||||
|
- 用户名:不加默认切换到root
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
作用:sudo用来在非root账户上用root权限执行指令
|
||||||
|
|
||||||
|
使用权限:在sudo组的账号,例如创建系统时的账号
|
||||||
|
|
||||||
|
案例:
|
||||||
|
- sudo su - //用sudo来切换到root账号
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# systemctl \[start | stop | status | enable | disable] \[服务名]
|
||||||
|
|
||||||
|
作用:控制软件(内置或第三方)的:启动、停止、开机自启 | 单指令查看进程状态
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- systemctl
|
||||||
|
- systemctl enable chrony
|
||||||
|
- systemctl install nginx
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# top \[-p -d -c -n -b -i -u]
|
||||||
|
|
||||||
|
作用:默认每5s刷新一次系统性能信息
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- p:只显示某个进程的信息
|
||||||
|
- d:设置双向时间,默认5s
|
||||||
|
- c:显示产生进程的完整命令,默认是进程名
|
||||||
|
- n:指定刷新次数,-n 3表示刷新3次后退出
|
||||||
|
- b:以非交互非全屏模式运行,以批次的方式执行top,一般配合-n指定输出几次统计信息,将输出重定向到指定文件,例如top -b -n 3 > /tmp/top.tmp
|
||||||
|
- i:不显示任何限制或无用的进程
|
||||||
|
- u查找指定用户启动的进程
|
||||||
|
|
||||||
|
交互式选项模式:
|
||||||
|
- h:显示帮助画面
|
||||||
|
- c:显示进程的完整命令
|
||||||
|
- f:选择需要展示的项目
|
||||||
|
- M:更具驻留内存大小(RES)排序
|
||||||
|
- P:根据CPU使用百分比大小进行展示
|
||||||
|
- T:根据时间/累计时间进行排序
|
||||||
|
- E:切换顶部内存显示单位
|
||||||
|
- e:切换进程内存显示单位
|
||||||
|
- l:切换显示平均负载和启动时间信息
|
||||||
|
- i:不显示限制或无用进程,和i参数相同
|
||||||
|
- t:切换显示CPU状态信息
|
||||||
|
- m:切换显示内存信息
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- top
|
||||||
|
|
||||||
|
信息:
|
||||||
|
- 横向信息:
|
||||||
|
- 第一行:
|
||||||
|
- top:当前系统时间
|
||||||
|
- up:开机时间
|
||||||
|
- users:登录的用户数
|
||||||
|
- load average:1/5/15分钟内系统平均负载
|
||||||
|
- 第二行:
|
||||||
|
- task:进程数
|
||||||
|
- running:正在运行的进程
|
||||||
|
- sleeping:睡眠的进程
|
||||||
|
- stopped:停止的进程
|
||||||
|
- zombie:僵尸进程
|
||||||
|
- 第三行:
|
||||||
|
- cpus
|
||||||
|
- us:用户占用率
|
||||||
|
- sy:系统占用率
|
||||||
|
- ni:高优先进程占用率
|
||||||
|
- id:空闲cpu百分比
|
||||||
|
- wa:IO等待CPU占用率
|
||||||
|
- hi:CPU硬件中断率
|
||||||
|
- si:CPU软件中断率
|
||||||
|
- st:强制等待占用CPU率
|
||||||
|
- 第四行、第五行:
|
||||||
|
- Kib Mem:物理内存
|
||||||
|
- total:总量
|
||||||
|
- free:空闲大小
|
||||||
|
- used:使用中的大小
|
||||||
|
- buff/cache:缓存使用大小
|
||||||
|
- Kib Swap:虚拟内存
|
||||||
|
- 同样
|
||||||
|
- 竖向信息:
|
||||||
|
- PID:进程id
|
||||||
|
- USER:进程所属用户
|
||||||
|
- PR:进程优先级,越小越高
|
||||||
|
- NI:负值标识高优先级,正标识低优先级
|
||||||
|
- VIRT:进程使用虚拟内存,单位KB
|
||||||
|
- RES:进程使用物理内存,单位KB
|
||||||
|
- SHR:进程使用共享内存,单位KB
|
||||||
|
- S:进程状态(S休眠,R运行,Z僵死,N附属优先级,I空闲状态)
|
||||||
|
- %CPU:CPU占用率
|
||||||
|
- %MEM:进程占用率
|
||||||
|
- TIME+:进程使用CPU时间总计,单位10ms
|
||||||
|
- COMMAND:进程的命令或名称或程序文件路径
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# touch \[路径]
|
||||||
|
|
||||||
|
作用:创建文件
|
||||||
|
|
||||||
|
示例:
|
||||||
|
touch test.txt
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# 创建用户:useradd \[-g -d] \[用户名]
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -g:指定用户的组,不指定会创建同名组并加入,如果有同名组必须用-g
|
||||||
|
- -d:指定用户的home路径,默认在`/home/用户名`下
|
||||||
|
|
||||||
|
案例:
|
||||||
|
- useradd -g dev kister
|
||||||
|
|
||||||
|
|
||||||
|
# 删除用户:userdel \[-r] \[用户名]
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- -r:删除用户的HOME目录,附带即可无需指定path
|
||||||
|
案例:
|
||||||
|
- userdel -r kister
|
||||||
|
|
||||||
|
# 查询用户所属组:id \[用户名]
|
||||||
|
|
||||||
|
# 修改用户:usermod \[-aG] \[用户组] \[用户名]
|
||||||
|
|
||||||
|
作用:将指定的用户加入指定的用户组中
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- aG:加入用户组
|
||||||
|
案例:
|
||||||
|
- usermod -aG sudo kister
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# wget \[-b] \[url]
|
||||||
|
|
||||||
|
作用:下载文件
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- b:后台下载,会在当前工作目录下写wget-log日志
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- apache-
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
这些指令都是程序,所以执行的命令的程序也需要存放
|
||||||
|
|
||||||
|
# which \[参数]
|
||||||
|
|
||||||
|
参数:命令
|
||||||
|
|
||||||
|
作用:查询指令程序的地址
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- which pwd
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
作用:查看当前用户
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# yum \[-y] \[install | remove | serach] \[软件名称]
|
||||||
|
|
||||||
|
前提条件:
|
||||||
|
- yum需要root权限
|
||||||
|
|
||||||
|
参数:
|
||||||
|
- y:自动确认,不用手动按y
|
||||||
|
- install:安装
|
||||||
|
- remove:卸载
|
||||||
|
- search:搜索
|
||||||
|
|
||||||
|
案例:
|
||||||
|
- yum -y install wget
|
||||||
|
|
||||||
|
安装包:
|
||||||
|
- .rpm
|
||||||
@@ -5,4 +5,4 @@ command \[-options] \[parameter]
|
|||||||
|
|
||||||
示例:
|
示例:
|
||||||
- ls -l /home/* 以列表的形式,显示/home/* 目录下所有的文件
|
- ls -l /home/* 以列表的形式,显示/home/* 目录下所有的文件
|
||||||
- cp -r test1 test2 赋值文件夹test1为test2
|
- cp -r test1 test2 复制文件夹test1为test2
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# 反引号/飘号:\`
|
||||||
|
|
||||||
|
作用:把包裹的内容作为命令执行
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- echo \`pwd\`
|
||||||
|
|
||||||
|
# 重定向符 >
|
||||||
|
|
||||||
|
作用:
|
||||||
|
- >:将左侧命令的结果,覆盖写入到右侧指定的文件中
|
||||||
|
- >>:将左侧命令的结果,追加写入到右侧指定的文件中
|
||||||
|
|
||||||
|
示例:
|
||||||
|
- echo "this is a added line" >> test.txt
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# 工作模式
|
||||||
|
## 命令模式
|
||||||
|
命令模式下,所有输入都理解为命令,以命令驱动不同的功能
|
||||||
|
输入vi指令后进入
|
||||||
|
## 输入模式
|
||||||
|
正常的编辑模式、插入模式
|
||||||
|
可以对内容进行自由编辑
|
||||||
|
ESC退出
|
||||||
|
## 底线命令模式
|
||||||
|
以:开始,通常用于文件的保存
|
||||||
|
按下:开始
|
||||||
|
|
||||||
|
# 命令:
|
||||||
|
进入命令模式:
|
||||||
|
- vim \[文件]
|
||||||
|
如果文件不存在会自动创建
|
||||||
|
|
||||||
|
|
||||||
|
按下ESC:无论在哪儿都回到命令模式
|
||||||
|
命令模式:
|
||||||
|
- i:进入输入模式
|
||||||
|
- I:在当前行的开头进入输入模式
|
||||||
|
- a:在当前光标位置 的后进入输入模式
|
||||||
|
- A:在当前行的结尾进入输入模式
|
||||||
|
- o:在当前光标下一行进入输入模式
|
||||||
|
- O:在当前光标上一行进入输入模式
|
||||||
|
- -----------------------------
|
||||||
|
- ↑、k:上移
|
||||||
|
- ↓、j:下移
|
||||||
|
- ←、h:左移
|
||||||
|
- →、l:右移
|
||||||
|
- 0:移动到当前行开头
|
||||||
|
- $:移动到当前行结尾
|
||||||
|
- pageup:上翻页
|
||||||
|
- pagedown:下翻页
|
||||||
|
- ---
|
||||||
|
- /:进入搜索模式
|
||||||
|
- n:向下继续搜索
|
||||||
|
- N:向上继续搜索
|
||||||
|
- ---
|
||||||
|
- yy:复制一行
|
||||||
|
- nyy:n是数字,复制多行
|
||||||
|
- P:粘贴
|
||||||
|
- dd:删除一行
|
||||||
|
- ndd:n是数字,删除多行
|
||||||
|
- u:撤销
|
||||||
|
- ctrl+r:撤销 撤销指令
|
||||||
|
- gg:跳到开头
|
||||||
|
- G:跳到结尾
|
||||||
|
- dG:从当前行开始,向下全部删除
|
||||||
|
- dgg:从当前行开始,向上全部删除
|
||||||
|
- d$:从光标开始,删除到本行结尾
|
||||||
|
- d0:从光标开始,删除到本行的开头
|
||||||
|
|
||||||
|
输入模式:
|
||||||
|
- 进行任意内容的更改
|
||||||
|
|
||||||
|
底线命令模式:
|
||||||
|
- 输入`":"`:进行入底线命令模式
|
||||||
|
- w:保存
|
||||||
|
- q:退出
|
||||||
|
- !:强制执行
|
||||||
|
- set nu:显示行号
|
||||||
|
- set paste:设置粘贴模式
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
ctrl+l:清空控制台
|
|
||||||
|
|
||||||
ctrl+w:删除指令的最近一部分
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
相关指令:chmod
|
||||||
|
前提:文件或文件夹的所属用户或root用户
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
## ls -l的信息
|
||||||
|
### 第一组:权限控制信息
|
||||||
|
- 样式:drwxr-xr-x
|
||||||
|
- 作用:描述权限控制信息
|
||||||
|
详解:
|
||||||
|
- 总共分为10个槽位
|
||||||
|
- 第1槽位:表示信息状态
|
||||||
|
- 状态:-或d或l
|
||||||
|
- -:表示文件
|
||||||
|
- d:表示文件夹
|
||||||
|
- l:表示软连接
|
||||||
|
- 2至4三个槽位:表示所属用户权限
|
||||||
|
- 5至7三个槽位:表示所属用户组权限
|
||||||
|
- 8至10三个槽位:表示其他用户权限
|
||||||
|
- 后面三组三个权限细节:
|
||||||
|
- 状态:r、w、x或-
|
||||||
|
- 第一个槽:r或-,读权限
|
||||||
|
- 第二个槽:w或-,写权限
|
||||||
|
- 第三个槽:x或-,执行权限
|
||||||
|
|
||||||
|
### 第二组:硬链接数
|
||||||
|
- 样式:单个数字
|
||||||
|
- 作用:表述文件或目录的硬链接数
|
||||||
|
### 第三组:用户名
|
||||||
|
- 样式:\[用户名]
|
||||||
|
### 第四组:用户组
|
||||||
|
- 样式:\[用户组]
|
||||||
|
|
||||||
|
## 常用场景细节
|
||||||
|
###### 1.删除文件需要什么权限,w吗?
|
||||||
|
不!删除文件需要你有被删除文件父文件夹的w和x权限
|
||||||
|
###### 2.文件夹没有读权限,能进去查看吗?
|
||||||
|
不相干,可以总结为:rx能cd能ls,单x能进去无法ls,单r进去不也ls不了
|
||||||
|
想进去文件夹,需要有文件夹的执行x权限(依赖cd)
|
||||||
|
想查看文件夹(ls),需要有文件夹的读rx权限(ls需要x执行权限进去,没有x也不能r)
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Root用户:拥有最大的权限,可以增删改查所有内容包括系统本身,默认密码不存在
|
||||||
|
|
||||||
|
sudo passwd -S root显示L标识密码锁定
|
||||||
|
|
||||||
|
切换到root的指令用[[su]]
|
||||||
|
因为默认密码不存在,一般的su - root无法切换到root
|
||||||
|
|
||||||
|
使用普通用户切换到其他用户需要输入密码
|
||||||
|
使用root用户切换到其他用户无需输入密码
|
||||||
|
|
||||||
|
一种基于[[sudo指令]]组用户切换到root指令:sudo - su
|
||||||
|
sudo用户:创建系统时的用户
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
切换到root用户后,执行指令:visudo
|
||||||
|
该指令会自动通过vi打开/etc/sudoers
|
||||||
|
|
||||||
|
在文件中添加
|
||||||
|
`用户名 ALL=(ALL) NOPASSWD:ALL`
|
||||||
|
NOPASSWD表示使用sudo命令无需输入密码
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
Linux支持:
|
||||||
|
- 配置多个用户
|
||||||
|
- 配置多个用户组
|
||||||
|
- 一个用户加入多个用户组
|
||||||
|
|
||||||
|
Linux的权限管控有两个级别,分别是:
|
||||||
|
- 针对用户的权限控制
|
||||||
|
- 针对用户组的权限控制
|
||||||
|
针对某个文件,可以控制用户的权限,也可以控制用户组的权限
|
||||||
|
|
||||||
|
# 用户组
|
||||||
|
相关命令:(root权限)
|
||||||
|
- 创建:[[groupadd&groupdel|groupadd]]
|
||||||
|
- 删除:[[groupadd&groupdel|groupdel]]
|
||||||
|
|
||||||
|
# 用户
|
||||||
|
相关命令:
|
||||||
|
- [[useradd&userdel&id&usermod|useradd]]
|
||||||
|
- [[useradd&userdel&id&usermod|userdel]]
|
||||||
|
- [[useradd&userdel&id&usermod|id]]
|
||||||
|
- [[useradd&userdel&id&usermod|usermod]]
|
||||||
|
- [[whoami]]
|
||||||
|
- [[passwd]]
|
||||||
|
# 查询用户/用户组:
|
||||||
|
- [[getent]] passwd
|
||||||
|
- [[getent]] group
|
||||||
|
- [[groups]]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# 相关指令:
|
||||||
|
- [[hostname]]
|
||||||
|
|
||||||
|
# ip地址:
|
||||||
|
|
||||||
|
在网络上唯一的地址,用于标识身份,有v4和v6
|
||||||
|
|
||||||
|
127.0.0.1:标识本机
|
||||||
|
0.0.0.0:指所有IP的意思,可以在端口绑定中用来绑定关系,或有其他作用
|
||||||
|
|
||||||
|
### 相关指令:
|
||||||
|
- ifconfig(没有安装net-tools)
|
||||||
|
|
||||||
|
# 主机名:
|
||||||
|
|
||||||
|
计算机的名字,也是用来标识的
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
作用:存放域名信息方便解析IP
|
||||||
|
|
||||||
|
位置:
|
||||||
|
- windows:c:\windows\system32\drivers\etc\hosts
|
||||||
|
- linux:/etc/hosts
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
相关指令:
|
||||||
|
- [[top]]
|
||||||
|
- [[df]]
|
||||||
|
- [[iostat]]
|
||||||
|
- [[sar]]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
- NetworkManager:主网络服务
|
||||||
|
- network:副网络服务
|
||||||
|
- firewalld:防火墙
|
||||||
|
- sshd,ssh:远程
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
场景操作系统的安装方式:
|
||||||
|
- 用安装包:exe、msi等
|
||||||
|
- 应用商店:Microsoft Store等
|
||||||
|
linux:
|
||||||
|
- [[yum(CentOS或RHEL)]]
|
||||||
|
- [[apt(Ubuntu或Debian)]]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Ctrl+l:清空控制台
|
||||||
|
|
||||||
|
Ctrl+w:删除指令的最近一部分
|
||||||
|
|
||||||
|
Ctrl+d:返回上一个用户
|
||||||
|
|
||||||
|
Ctrl+c:强制停止程序运行
|
||||||
|
|
||||||
|
Ctrl+r:输入命令相关字符,匹配最近一次输入的相关指令
|
||||||
|
|
||||||
|
Ctrl+a:移动到指令开始
|
||||||
|
|
||||||
|
Ctrl+e:移动到指令结尾
|
||||||
|
|
||||||
|
Ctrl+←:向左跳转一个单词
|
||||||
|
|
||||||
|
Ctrl+→:向右跳转一个单词
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
相关文件:/etc/sysconfig/network-scripts/ifcfg-ens33
|
||||||
|
|
||||||
|
修改内容:
|
||||||
|
- BOOTPROTO="static" (不填DHCP
|
||||||
|
新增内容:
|
||||||
|
- IPADDR="XXX.XXX.XXX.XXX"
|
||||||
|
- NETMASK="XXX.XXX.XXX.XXX"
|
||||||
|
- GATEWAY="XXX.XXX.XXX.XXX"
|
||||||
|
- DNS1="XXX.XXX.XXX.XXX"
|
||||||
|
|
||||||
|
重启网卡:
|
||||||
|
- systemctl restart network
|
||||||
|
|
||||||
|
### VMware虚拟机的设置
|
||||||
|
1. 编辑>虚拟网络编辑器
|
||||||
|
2. VMnet8>确认/修改 子网IP和子网掩码
|
||||||
|
3. NAT设置>设置网关
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
相关命令:
|
||||||
|
- [[date]]
|
||||||
|
- [[ntpd]]
|
||||||
|
|
||||||
|
修改日期和时间:
|
||||||
|
1. 切换到root
|
||||||
|
2. 删除/etc/localtime
|
||||||
|
3. 创建一个软连接把/user/share/zoneinfo/Asia/Shanghai放回去
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
相关指令:
|
||||||
|
- [[netstat]]
|
||||||
|
- [[nmap]]
|
||||||
|
|
||||||
|
不同服务/程序有不同端口
|
||||||
|
|
||||||
|
公认端口:1-1023
|
||||||
|
注册端口:1024-49151
|
||||||
|
动态端口:49152-65535
|
||||||
|
|
||||||
|
常见端口:
|
||||||
|
- 网页服务:
|
||||||
|
- 80:HTPP
|
||||||
|
- 443:HTTPS
|
||||||
|
- 8080:HTTP代理或备用端口,常用于测试环境或 Tomcat 默认端口。
|
||||||
|
- 8443:HTTPS备用端口,常用于需要 SSL 加密的管理后台
|
||||||
|
- 远程登录与服务器管理:
|
||||||
|
- 22:SSH
|
||||||
|
- 23:Telnet
|
||||||
|
- 3389:RDP,Windows远程
|
||||||
|
- 5900:VNC,用于图形化远程桌面
|
||||||
|
- 文件传输:
|
||||||
|
- 20:FTP数据端口
|
||||||
|
- 21:FTP控制端口
|
||||||
|
- 22:SFTP
|
||||||
|
- 69:TFTP
|
||||||
|
- 数据库:
|
||||||
|
- 3306:MySQL / MariaDB(关系型数据库)
|
||||||
|
- 5432:PostgreSQL(关系型数据库)
|
||||||
|
- 6389:Redis(内存缓存/键值对数据库)
|
||||||
|
- 27017:MongoDB(文档型 NoSQL 数据库)
|
||||||
|
- 14433:SQL Server(微软数据库)
|
||||||
|
- 1521:Oracle(甲骨文数据库)
|
||||||
|
- 邮件服务:
|
||||||
|
- 25:SMTP发信
|
||||||
|
- 110:POP3收信
|
||||||
|
- 143:IMAP收信
|
||||||
|
- 465/587加密的SMTP发信
|
||||||
|
- 网络基础服务:
|
||||||
|
- 53:DNS
|
||||||
|
- 67/68:DHCP
|
||||||
|
- 123:NTP网络时间协议
|
||||||
|
- 161:SNMP简单网络管理协议
|
||||||
|
- 开发与中间件:
|
||||||
|
- 2182:ZooKeeper分布式协调服务
|
||||||
|
- 9092:Kafka消息队列,分布式流处理
|
||||||
|
- 9200:Elasticsearch搜索引擎,HTTP API 端口
|
||||||
|
- 9300:Elasticsearch集群内部通信端口
|
||||||
|
- 8080/8090:很多 Java 微服务(如 Spring Boot)的默认端口
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
相关命令:
|
||||||
|
- [[ping]]
|
||||||
|
- [[wget]]
|
||||||
|
- [[curl]]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
作用:将文件、文件夹链接到其他位置,类似快捷方式
|
||||||
|
|
||||||
|
相关指令:[[ln]]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
相关指令:
|
||||||
|
- [[ps]]
|
||||||
|
- [[kill]]
|
||||||
|
|
||||||
|
每个在运行的程序都有相应的实例:进程
|
||||||
|
每一个进程都有进程号(PID)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user