咖啡丶七

自律给我自由

安装

下载包体

网站:nginx: download

上传解压

tar -zxvf nginx-1.24.0.tar.gz

编译

./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module

make

make install

环境配置

设置快捷键

ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

这样执行/usr/bin/nginx就相当于执行了/usr/local/nginx/sbin/nginx

而/usr/bin/是全局可用的,所以在任何地方输入nginx都可以执行/usr/lcoal/nginx/sbin/nginx

使用下面命令实时查看log更新

1
less +F access.log

安装

下载包体

官网网址:MySQL :: MySQL Community Downloads

将文件解压到一个新建的文件夹中tar -xvf mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar -C mysql-8.0.33

安装openssl-devel插件,mysql里有些rpm的安装依赖于该插件

安装rpm包

依次执行以下命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 共享的 MySQL 通用文件,可能包括一些共享的配置文件等。这是 MySQL 安装的一部分,通常需要安装
rpm -ivh mysql-community-common-8.0.33-1.el7.x86_64.rpm
# MySQL 客户端插件,提供额外的功能和扩展。具体需要哪些插件取决于你的使用情况。你可以根据你的需要来决定是否安装这些插件。
rpm -ivh mysql-community-client-plugins-8.0.33-1.el7.x86_64.rpm
# MySQL 库文件,用于在应用程序中连接到 MySQL 数据库。这是 MySQL 连接所必需的,通常需要安装
rpm -ivh mysql-community-libs-8.0.33-1.el7.x86_64.rpm
# 共享的 MySQL 通用文件,可能包括一些共享的配置文件等。这是 MySQL 安装的一部分,通常需要安装
rpm -ivh mysql-community-libs-compat-8.0.33-1.el7.x86_64.rpm
# MySQL 开发包,包含开发所需的头文件和库文件。如果你打算在该系统上开发与 MySQL 相关的应用程序,你需要安装此包
rpm -ivh mysql-community-devel-8.0.33-1.el7.x86_64.rpm
# MySQL 客户端工具,用于连接和管理 MySQL 服务器。通常情况下,如果你计划从该系统上远程连接到其他 MySQL 服务器,你需要安装此包。如果你的系统不需要连接其他 MySQL 服务器,则可能不需要安装
rpm -ivh mysql-community-client-8.0.33-1.el7.x86_64.rpm
# ICU 数据文件,用于支持国际化和字符集处理。如果你的应用程序不需要特定的国际化功能,则可能不需要安装
rpm -ivh mysql-community-icu-data-files-8.0.33-1.el7.x86_64.rpm
# MySQL 服务器,用于托管数据库实例。如果你计划在该系统上安装 MySQL 数据库服务器,你需要安装此包
rpm -ivh mysql-community-server-8.0.33-1.el7.x86_64.rpm

常用命令

启动

使用systemctl start mysqld命令启动服务器

rpm安装MySQL会自动生成一个随机密码,可以在/var/log/mysqld.log中查看

使用mysql -u root -p进入客户端

设置密码

连接MySQL之后,使用ALTER USER 'root'@'localhost' IDENTIFIED BY '123456789';修改密码

出现Your password does not satisfy the current policy requirements提示,意思是您的密码不符合当前规定的要求,你要么就把你的密码设置得复杂点,要么就去降低密码的校验规则。

在 Linux 上安装 MySQL 时会自动安装一个校验密码的插件,默认密码检查策略要求密码必须包含:大小写字母、数字和特殊符号,并且长度不能少于8位。修改密码时新密码是否符合当前的策略,不满足则会提示ERROR

可以将这个限制密码位数设小一点,复杂度类型调底一点

1
2
3
4
# 将密码复杂度校验调整简单类型
set global validate_password.policy = 0;
# 设置密码最少位数限制为 4 位
set global validate_password.length = 4;

远程连接

可能遇到的问题

MySQL自身原因

MySQL默认不允许远程连接,修改配置

  1. 使用mysql -u root -p链接服务器
  2. show databases;查看当前所有数据库
  3. use mysql;进入mysql数据库(配置mysql的一个数据库)
  4. select user,host from user;查看用户的链接方式
  1. 使用update user set host='%' where user='root';将root的链接方式修改为%
  2. systemctl restart mysqld重启mysql服务器

外在原因

  1. MySQL是否关掉了
  2. 防火墙的3306端口是否对外开放了
  3. 如果你是云服务器还需要开放3306的安全组
1
2
3
4
# 开放80端口,`--premanent`表示永久开放,重启后也依然开放
sudo firewall-cmd --zone=public --add-port=80/tcp --permanent
# 重新加载防火墙
firewall-cmd --reload

参考连接:Linux-安装MySQL(详细教程)

单例模式

懒汉模式:

指在第一次访问单例对象时才创建实例

特点是在多线程环境下可能会存在线程安全问题,因为多个线程可能在同一时间检查到实例不存在,从而导致多个实例被创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class UnitySingleton<T> : MonoBehaviour
where T : Component
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType(typeof(T)) as T;
if (_instance == null)
{
GameObject obj = new GameObject();
_instance = obj.AddComponent<T>();
}
}
return _instance;
}
}
}

饿汉模式:

指在类加载时就创建实例,无论是否需要

这样就可以避免多线程环境下的线程安全问题,但可能会增加启动时间和内存消耗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour, new()
{
public static T Instance = null;

public virtual void Awake()
{
if (Instance == null)
{
Instance = this as T;
}
else
{
Destroy(this.gameObject);
Debug.LogError("单例只允许存在一个,架构存在错误,本物体" + this.name + " 已删除");
}
}
}

拓展:

懒汉模式下,结束运行时可能会报错Some objects were not cleaned up when closing

这是因为我们在OnDestroy里访问了这个单例,结束运行时这个单例已经变成null

访问这个单例的时候又产生了一个新的实例才会报这个错误

可以将上述懒汉单例改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class UnitySingleton<T> : MonoBehaviour
where T : Component
{
private static bool applicationIsQuitting = false;
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
if (applicationIsQuitting)
return _instance;
_instance = FindObjectOfType(typeof(T)) as T;
if (_instance == null)
{
GameObject obj = new GameObject();
_instance = obj.AddComponent<T>();
}
}
return _instance;
}
}

protected virtual void OnDestory()
{
applicationIsQuitting = true;
}
}

观察者模式

使用委托和事件实现

下面的方法使用的是委托和列表的方式,原理是一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventManager : Singleton<EventManager>
{
public delegate void EventCallBack(object param);// 事件回调函数
// 事件字典,键可以用枚举来实现
Dictionary<int, List<EventCallBack>> mDictEvent = new Dictionary<int, List<EventCallBack>>();

/// <summary>
/// 添加事件监听
/// </summary>
public void AddEvent(int eventId, EventCallBack callBack)
{
if(!mDictEvent.ContainsKey(eventId))
{
mDictEvent.Add(eventId,new List<EventCallBack>());
}
if(!mDictEvent[eventId].Contains(callBack))
{
mDictEvent[eventId].Add(callBack);
}
else
{
Debug.LogWarning("Repeat Add Event CallBack,EventId = " + eventId + ",CallBack = " + callBack.ToString());
}
}

/// <summary>
/// 删除事件监听
/// </summary>
public void DelEvent(int eventId, EventCallBack callBack)
{
if(!mDictEvent.ContainsKey(eventId))
{
return;
}
if(!mDictEvent[eventId].Contains(callBack))
{
return;
}
mDictEvent[eventId].Remove(callBack);

// 如果回调都被移除了 那么key也从字典移除
if (mDictEvent[eventId].Count < 1)
{
mDictEvent.Remove(eventId);
}

}

/// <summary>
/// 通知事件
/// </summary>
public void NotifyEvent(int eventId,object param)
{
if(mDictEvent.ContainsKey(eventId))
{
foreach(var callback in mDictEvent[eventId])
{
callback(param);
}
}
}
}

组合模式

把公共方法抽象成组件,需要用到这个方法的对象可以将对应的组件添加到该对象上

比较简单,就不举例了


命令模式

适用场景:实现撤销功能

大致由三部分组成:命令类、命令管理器类、输入类

命令类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using UnityEngine;

/// <summary>
/// 命令基类
/// </summary>
public abstract class CommandBase
{
/// <summary>
/// 执行
/// </summary>
public abstract void Execute();

/// <summary>
/// 撤销
/// </summary>
public abstract void Undo();
}

public class MoveForWard : CommandBase
{
private GameObject _player;
public MoveForWard(GameObject player)
{
_player = player;
}

public override void Execute()
{
_player.transform.Translate(Vector3.forward);
}

public override void Undo()
{
_player.transform.Translate(Vector3.back);
}
}

public class MoveLeft : CommandBase
{
private GameObject _player;
public MoveLeft(GameObject player)
{
_player = player;
}
public override void Execute()
{
_player.transform.Translate(Vector3.left);
}

public override void Undo()
{
_player.transform.Translate(Vector3.right);
}
}

命令管理器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CommandManager : MonoBehaviour
{
public static CommandManager Instance;
private readonly List<CommandBase> _commandList = new List<CommandBase>();

private void Awake()
{
if (Instance) Destroy(Instance);
else Instance = this;
}

public void AddCommands(CommandBase command)
{
_commandList.Add(command);
}

public IEnumerator UndoStart()
{
_commandList.Reverse();
foreach (CommandBase command in _commandList)
{
yield return new WaitForSeconds(.2f);
command.Undo();
}

_commandList.Clear();
}
}

输入类:

监听按键点击,只负责接受输入,具体的操作放在命令的Execute方法中,这样实现解耦
点击W或A键时执行命令,并把命令添加的管理器的列表中,点击B键撤销之前所有的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using UnityEngine;

public class InputHandler : MonoBehaviour
{
private MoveForWard _moveForward;
private MoveLeft _moveLeft;
private GameObject _playerCube;

private void Start()
{
_playerCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}

private void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
_moveForward = new MoveForWard(_playerCube);
_moveForward.Execute();
CommandManager.Instance.AddCommands(_moveForward);//顺序不能弄混,因为要等赋值完后再加入
}

if (Input.GetKeyDown(KeyCode.A))
{
_moveLeft = new MoveLeft(_playerCube);
_moveLeft.Execute();
CommandManager.Instance.AddCommands(_moveLeft);
}

if (Input.GetKeyDown(KeyCode.B))
{
StartCoroutine(CommandManager.Instance.UndoStart());
}
}
}

状态模式

一般使用有限状态机实现

  • 将对象的行为抽象成几个独立的状态
  • 某一时刻只能处于其中一种状态
  • 通过管理控制状态的互相切换

有两张使用场景:场景切换、怪物AI

核心代码(状态机):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System.Collections.Generic;
using UnityEngine;
using System;

namespace MY_FSM
{
public enum StateType
{
Idle,
MOVE,
Find_Enemy,
Attack,
Die,
Success,
}

/// 接口,AI的状态需要接收这个接口
public interface IState
{
void OnEnter();
void OnExit();
void OnUpdate();
// void OnCheck();
// void OnFixUpdate();
}

[Serializable]
public class Blackboard
{
// 此处存储共享数据,或者向外展示的数据,可配置的数据
}

public class FSM
{
public IState curState;
public Dictionary<StateType, IState> states;
public Blackboard blackboard;

public FSM(Blackboard blackboard)
{
this.states = new Dictionary<StateType, IState>();
this.blackboard = blackboard;
}

public void AddState(StateType stateType, IState state)
{
if (states.ContainsKey(stateType))
{
Debug.Log("[AddState] >>>>>>>>>>>>> map has contain key: " + stateType);
return;
}
states.Add(stateType, state);
}

public void SwitchState(StateType stateType)
{
if (!states.ContainsKey(stateType))
{
Debug.Log("[SwitchState] >>>>>>>>>>>>>>>>> not contain key: " + stateType);
return;
}
if (curState != null)
{
curState.OnExit();
}
curState = states[stateType];
curState.OnEnter();
}

public void OnUpdate()
{
curState.OnUpdate();
}

public void OnFixUpdate()
{
// curState.OnFixUpdate();
}

public void OnCheck()
{
// curState.OnCheck();
}
}
}

装饰器

装饰器可以灵活的控制两个函数的执行顺序

无返回值

1
2
3
4
5
6
7
8
def sum(func):
print(1)
func()
print(3)

@sum
def take():
print(2)

输出结果

1
2
3
1
2
3

有返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def outer(func):
print("outer") # ----------1
def wrapper(x, y): # ----------3
print("wrapper") # ----------4
res = func(x, y) # ----------5
return res # ----------9
return wrapper # ----------2


@outer
def inner(x, y): # ----------6
print("inner") # ----------7
return x+y # ----------8


print(inner(1,2))

输出结果

1
2
3
4
outer
wrapper
inner
3

上下文管理器

在 Python 中,上下文管理器常常与 with 语句一起使用。with 语句会在代码块进入时调用上下文管理器的 __enter__() 方法,而在代码块退出时会调用上下文管理器的 __exit__() 方法。这种机制确保了资源在适当的时候被初始化和清理。

最基础的上下管理器:

1
2
with open("a.txt", 'r') as file:
file.read()

自己定义一个上下文管理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class MyContext:
def __enter__(self):
print("Entering the context")
return self

def __exit__(self, exc_type, exc_value, traceback):
"""
exc_type: 异常类型,如果没有异常则为None
exc_value: 异常值,如果没有异常则为None
traceback: 追溯信息,如果没有异常则为None
"""
print("Exiting the context")
if exc_type is not None:
print(f"An exception of type {exc_type} occurred with value {exc_value}")
return False # Return True if you want to suppress the exception

# 使用with语句创建上下文管理器
with MyContext() as context:
print("Inside the context")

print("Outside the context")

输出

1
2
3
4
Entering the context
Inside the context
Exiting the context
Outside the context

contextlib模块

基础用法

上面我们自定义上下文管理器确实很方便,但是Python标准库还提供了更加易用的上下文管理器工具模块contextlib,它是通过生成器实现的,我们不需要再创建类以及__enter____exit__这两个特俗的方法:

1
2
3
4
5
6
7
8
9
10
11
12
from contextlib import contextmanager

@contextmanager
def make_open_context(filename, mode):
fp = open(filename, mode)
try:
yield fp
finally:
fp.close()

with make_open_context('/tmp/a.txt', 'a') as file_obj:
file_obj.write("hello carson666")

在上文中,yield关键词把上下文分割成两部分:

  • yiled之前就是__enter__中的代码块
  • yield之后就是__exit__中的代码块

yeild生成的值会绑定到with语句的as子句中的变量。例如上面的例子中yield生成的值是文件句柄对象fp,在下面的with语句中,会将fpfile_obj绑定到一起,也就是说file_obj此时就是一个文件句柄对象,那么它就可以操作文件了,因此就可以调用file_obj.write("hello world")

另外要注意的是,如果yield没有生成值,那么在with语句中就不需要写as子句了

将普通的类变为上下文管理器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from contextlib import contextmanager

class MyResource:
def query(self):
print("query data")

@contextmanager
def make_myresource():
print("connect to resource")
yield MyResource()
print("connect to resource")

with make_myresource() as r:
r.query()

输出

1
2
3
connect to resource
quert data
connect to resource

Union

作用:限制数据类型的范围

1
2
3
4
5
6
7
8
9
from typing import Union

def give_me_the_bigger_one(num0: Union[int, float], num1: Union[int, float]) -> Union[int, float]:
if type(num0) != type(num1):
raise ValueError(f"The two number {num0} and {num1} must have the same type!")
if num0 > num1:
return num0
else:
return num1

a: Union[int, float]表示变量a可以是int,也可以是float

扩展:
Any可以表示任意类型,如果写成a: Any那么就相当于没有做任何事,因为如果只写a的话本身就是能代指任意类型

TypeVar

制作模板——自己定义一个类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from typing import TypeVar


T = TypeVar("T")


def give_me_the_bigger_one(num0: T, num1: T) -> T:
if type(num0) != type(num1):
raise ValueError(f"The two number {num0} and {num1} must have the same type!")

if num0 > num1:
return num0
else:
return num1

T = TypeVar("T")表示定义了一个泛型类型变量T,并没有指定他的类型上限,也就是说传给这个函数的参数可以是任意类型

通常在创建泛型类变量时会使用bound参数指定上限:

1
2
3
4
5
6
7
8
from typing import TypeVar

# 定义了一个泛型类型变量T_Config,他的类上限是BasePluginConfig
# 意味着T_Config可以被替代为BasePluginConfig类型或BasePluginConfig的子类
T_Config = TypeVar("T_Config", bound=BasePluginConfig)

class BasePluginConfig():
pass

Generic

类似于where,限制传给一个函数的类型范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from typing import List, TypeVar, Generic

T = TypeVar('T')

class Queue(Generic[T]):
def __init__(self) -> None:
# 定义一个元素类型都是T的队列
self.items: List[T] = []

def push(self, item: T) -> None:
self.items.append(item)

def pop(self) -> T:
return self.items.pop(0)

def __str__(self):
return str(self.items)

q = Queue[int]()
q.push(0)
q.push(1)
q.pop() # 移除0
q.push('string') # 并不会报错
print(q)

输出

1
2
3
[1, 'string']

进程已结束,退出代码0

注意最后的q.push('string')'string'虽然并不是int类型,但是在实际运行中并不会报错,不过我们可以通过使用静态类型检查工具(mypy, pytype, pyright, pyre)等方法,提前发现这些错误。这也是推荐使用typing模块来做type annotation的理由之一。

总结

  • 使用typing模块盒注释来提高代码的可读性

  • 将自动化的类型检查工具和API生成工具部署在CI中,方便提前发现错误,方便新人员的理解

参考:

Python中的泛型

委托

委托可以把一个方法代入另一个方法,相当于指向函数的指针,换句话说,委托相当于一个函数指针

总的来说,委托是一个类,该类内部维护着一个字段,指向一个方法。

委托的声明:public delegate void DoDelegate();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 测试方法
void Test(object sender, EventArgs e)
{
Console.Write($"valueStr={sender}");
}
// 定义委托
public delegate void DoDelegate(object sender, EventArgs e);

// 实例化委托——只是实例化,并不会执行
DoDelegate doDelegate = new DoDelegate(Test);
object sender = 888;
EventArgs e = new EventArgs(); // EventArgs是自定义事件,这里想要表达的意思是委托的参数不单只能是数值,还能是事件
// 执行委托的两种方法
// 方法一:
doDelegate?.Invoke(sender, e);
// 方法二:
doDelegate(sender, e);

泛型委托

我们每次要使用一个委托时,都需要先声明这个委托类,规定参数和返回值类型,然后才能实例化、调用。为了简化这个过程, .NET 框架为我们封装了三个泛型委托类,因此大部分情况下我们不必再声明委托,可以拿来直接实例化使用,方便了我们的日常写代码。
这三种泛型委托包括:Func委托、Action委托和Predicate委托。

Func委托

Func委托代表着拥有返回值的泛型委托。Func有一系列的重载,形式如 Func<T1,T2, … TResult>,其中TResult代表委托的返回值类型,其余均是参数类型。只有一个T时,即Func,代表该委托是无参数的。.NET封装了最多16个输入参数的Funct<>委托。
需要特别注意的是,若方法没有返回值,即返回 void ,由于 void 不是数据类型,因此不能定义Func委托。返回 void 的泛型委托见下文的Action。
Func的使用方法与一般的委托相同。例如上面的案例可改写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace delegateTest
{
class Program
{
static void Main(string[] args)
{
int calNum = Calculate(1, 2, Sub);
Console.WriteLine("calNum:{0}", calNum);// -1
}
static int Calculate(int num1, int num2, Func<int, int, int> calDel)
{
return calDel(num1,num2);
}
static int Sub(int num1, int num2)
{
Console.WriteLine("num1 - num2={0}", num1 - num2);
return num1 - num2;
}
}
}
Action委托

Action委托代表返回值为空 void 的委托,它也有一些列重载,最多拥有16个输入参数。用法与Func相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace delegateTest
{
class Program
{
static void Main(string[] args)
{
DoSome("hello",Say);// hello
}
static void DoSome(string str,Action<string> doAction)
{
doAction(str);
}
static void Say(string str)
{
Console.WriteLine(str);
}
}
}
Predicate委托

这个一般用的比较少,它封装返回值为bool类型的委托,可被Func代替。

匿名委托

采用匿名方法实例化的委托称为匿名委托。
每次实例化一个委托时,都需要事先定义一个委托所要调用的方法。为了简化这个流程,C# 2.0开始提供匿名方法来实例化委托。这样,我们在实例化委托时就可以 “随用随写” 它的实例方法。
使用的格式是:

委托类名 委托实例名= delegate(args) { 方法体代码 };

这样就可以直接把方法写在实例化代码中,不必在另一个地方定义方法。当然,匿名委托不适合需要采用多个方法的委托的定义。

使用匿名方法可以将最初的代码改写为:

1
2
3
4
5
6
7
8
9
10
11
public delegate void DoDelegate(object sender, EventArgs e);

DoDelegate doDelegate = delegate(sender, e)
{
Console.Write($"valueStr={sender}");
};

object sender = 888;
EventArgs e = new EventArgs(); // EventArgs是自定义事件,这里想要表达的意思是委托的参数不单只能是数值,还能是事件

doDelegate(sender, e); // 执行

Lambda表达式

纵然匿名方法使用很方便,可惜她很快就成了过气网红,没能领多长时间的风骚。如今已经很少见到了,因为delegate关键字限制了她用途的扩展。自从C# 3.0开始,她就被Lambda表达式取代,而且Lambda表达式用起来更简单。Lambda表达式本质上是改进的匿名方法。

表达式Lambda

当匿名函数只有一行代码时,可以采用这种形式:

1
2
3
4
5
6
7
8
public delegate void DoDelegate(object sender, EventArgs e);

DoDelegate doDelegate = (sender, e) => Console.Write($"valueStr={sender}");

object sender = 888;
EventArgs e = new EventArgs(); // EventArgs是自定义事件,这里想要表达的意思是委托的参数不单只能是数值,还能是事件

doDelegate(sender, e); // 执行
语句Lambda

当匿名函数有多行代码时,只能采用语句Lambda

1
2
3
4
5
6
7
8
9
10
11
12
public delegate void DoDelegate(object sender, EventArgs e);

DoDelegate doDelegate = (sender, e) => {
Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); // 打印当前方法的名称
Console.Write($"valueStr={sender}");
return;
};

object sender = 888;
EventArgs e = new EventArgs(); // EventArgs是自定义事件,这里想要表达的意思是委托的参数不单只能是数值,还能是事件

doDelegate(sender, e); // 执行

语句Lambda不能省略return。


事件

事件相当于保存委托的数组

事件是基于委托的,为委托提供一个订阅或发布的机制。事件是一种特殊的委托,调用事件和委托是一样的。

事件可以被看作是委托类型的一个变量,通过事件注册、取消多个委托和方法。

public event 委托类型 事件名称;
如:public event DoDelegate DoEvent;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 测试方法
void Test(object sender, EventArgs e)
{
Console.Write($"valueStr={sender}");
}
// 定义委托
public delegate void DoDelegate(object sender, EventArgs e);
// 定义事件
public event DODelegate DoEvent;

object sender = 888;
EventArgs e = new EventArgs();
// 两种用法
// 1.给事件注册委托
// 2.给事件直接注册方法
// 用法一(给事件注册委托):
// 给事件注册委托,可注册多个委托
DoEvent += new DoDelegate(doDelegate);
// 执行事件内所有的委托
DoEvent(sender, e);

// 用法二(给事件注册方法):
// 给事件注册方法,可注册多个方法
DoEvent += Test;
// 执行事件内所有的方法
DoEvent(sender, e);

忽略已跟踪的文件

.gitignore文件只能忽略未跟踪状态的文件,如果已经被跟踪了,可以使用下面的两种方法

git rm –cached <file>

彻底忽略该文件,push后,远程也将忽略该文件

如果远程仓库已经有了logs文件夹,使用三步完成

  1. 使用命令删除文件的跟踪状态 git rm --cached logs/
  2. 此时本地工作区修改还在,需要更新一下/gitignore文件
  3. 最后使用命令删除远程仓库对应的文件git add . && git commit -m "xx" && git push

skip-worktree和assume-unchanged

只在自己的工作区内忽略文件

skip-worktree

skip-worktree可以实现修改本地文件不会被提交,但又可以拉取最新更改需求。适用于一些不经常变动,但是必须本地化设置的文件

1
2
3
4
5
6
// 添加忽略文件
git update-index --skip-worktree <file>
// 取消忽略
git update-index --no-skip-worktree <file>
// 查看skip-worktree列表
git ls-files -v | grep '^S\'

assume-unchanged

该命令只是假设文件没有发生变动,使用reset时会将文件修改回去。当远程仓库相应的文件被修改时,pull更新之后,–assume-unchanged会被清楚

1
2
3
4
5
6
// 添加忽略文件
git update-index --assume-unchanged <file>
// 取消忽略
git update-index --no-assume-unchanged <file>
// 查看忽略了哪些文件
git ls-files -v | grep '^h\'

参考

一文带你彻底搞懂Git!


.gitignore文件

在此记录一下各个项目的.gitignore文件内容

https://github.com/github/gitignore/blob/main/Unity.gitignore

python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

Unity

项目中大量自动生成的*.meta文件是需要加入版本管理的

这个文件包含的信息:

  • 描述如何导入这个资产文件
  • 如何在项目中准备资产

根目录下的sln和csproj文件是为了能更好的使用Visual Studio,实际上Unity是用不上这个的,也是可以忽略掉的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/

# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/

# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta

# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*

# Autogenerated Jetbrains Rider plugin
/[Aa]ssets/Plugins/Editor/JetBrains*

# Visual Studio cache directory
.vs/

# Gradle cache directory
.gradle/

# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db

# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta

# Unity3D generated file on crash reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

# Crashlytics generated file
crashlytics-build.properties

# Packed Addressables
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*

# Temporary auto-generated Android Assets
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*

vs的C#项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# ASP.NET Scaffolding
ScaffoldingReadMe.txt

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd

C++

# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app


2023-08-04 跑步


2023-08-06 运动

5号回了趟老家,跑步鸽了一天,所以今天多跑一圈

2023-08-07 跑步


2023-08-08 跑步


2023-08-09 跑步


2023-08-10 跑步


2023-08-11 跑步


2023-08-18 运动

从上周五(11号)晚上开始二阳,到今天已经整整一周没有跑步了。

在这期间发觉自己的跑步习惯很不好,总是跑500m走200m,锻炼效果大打折扣。所以今天直接一口气跑完一圈

可惜的是今天的keep服务器有问题,一直访问不到服务器


2023-08-19 运动

今天也是一口气跑完一整圈

依旧没连上keep的服务器,重新下载了keep也还是连接不上。跑完后回到家发现居然可以连上了,太奇怪了


2023-08-20 运动

奇怪的很,每次要跑步的时候keep的服务器就连接不上去,跑完之后就能连上去了

可能是这个时间段跑步的人太多了,服务器响应不过来吧

机智的我今天是离线跑的,等重新连接上服务器之后再上传


2023-08-21 跑步


2023-08-22 运动

被自己蠢到,看了眼前两天的跑步记录,发现keep的账号登入成现在的手机号了(当前绑定的手机号是初中的时候用的一个手机号)

强迫症的我直接就注销+重新绑定一套流程走下来,好在中间没出什么岔子,很顺利的就绑定了好了

但是今天晚上的跑步记录没了,被自己蠢哭晕


2023-08-23 跑步


2023-08-25 跑步


2023-08-26 跑步


2023-08-27 跑步


2023-08-28 跑步


2023-08-29 跑步


2023-08-30 跑步


2023-08-31 运动

跑步跑太勤了,感觉我的这个老骨头快绷不住了。赶紧买了一瓶纯牛奶,结果发现错买成酸奶了
不过正好,我本来就不喜欢纯牛奶,并且喜欢酸奶,直接开干