工作机制
module
封装一系列可复用的功能,方便使用,分为内置Module与自定义Module
Cache
target
构建的产物,比如executable、library
常用Module、命令
include
从一个文件或者Module加载CMake代码
CMakeDependentOption
cmake_dependent_option
定义条件选项,在一定条件成立时才生效
封装一系列可复用的功能,方便使用,分为内置Module与自定义Module
构建的产物,比如executable、library
从一个文件或者Module加载CMake代码
定义条件选项,在一定条件成立时才生效
比特币源码是用C++写的,构建系统用的CMake,在CMakeLists.txt中可以找到add_executable命令,含义是最终构建的二进制产物,此命令的参数中会指定源文件。
进入加密货币行业4个月了,懵懵懂懂做了一些公司业务的需求,学了一些加密货币行业的皮毛知识,每天挂在嘴边的尽是些上链、签名、EVM、手续费等似是而非的名词。另一方面,Web3给我的体感是还在不断涌现新的项目,每次点开项目官网都有一种眩晕感,一开始还觉得这个项目又引领了一个创新,解决了Web3的重大难题,但是慢慢地,新鲜感一过,感受到的只有麻木,而且那么多币经我的手上链,感觉自己的提升并没有多少,只是对公司内部的技术栈以及工作流程更熟悉了而已。
静下心来想了一段时间,加密货币毕竟在国内游走在灰色地带,生态没有起来,中文社区的技术沉淀不够,对于新人入门很不友好。英文资料浩如烟海,虽然英语阅读对于我来说不是不可逾越的门槛,但是却也实打实地影响我的学习效率,一开始也想沉下心来慢慢学,但是时间被业务裹挟,始终没有开始做。终于,这段时间感觉学有余力了,狠狠心踏上BTC源码的学习之路。
直接说答案吧,值得!从大的方面讲,有以下两点:
一次做到完美不可能,粗略想了一下,分以下几步走:
宏(Macro)是C++里的一个让人又爱又恨的特性,非常难以掌握。然而,悲剧的是,许多大型C++项目中宏的使用满天飞,因此宏是一个C++程序员难以摆脱的特性,我们有必要梳理一下宏的用法。
Structural types | Nominal types | |
---|---|---|
Runtime checking | Duck typing | Goose typing |
Static checking | Static duck typing | Static typing |
本小节讨论表1第一列中的两种类型系统。
首先解释清楚一个概念,协议或者protocol,在Python中,这个概念可以理解为一个方法集合,其中的每个方法都有约定好的签名和语义,但在不同的类型系统下,对于用户自定义类的实现要求是不一样的。
对于Python原生支持的duck typing,程序员可以不必实现协议中的每一个方法,但是只在PEP 544被采纳之后才支持的static duck typing,严格要求实现协议中的每一个方法。在Python社区中,前者称之为动态协议,后者称之为静态协议,如果未明确指明的话,一般指动态协议。
两种形式的共同点是都无需显式声明所实现的协议,会有相对应的方法检查类的方法集合。
防御式编程的目的是增强程序的安全性,而Fail fast一方面通过尽早抛出异常来避免不可预料的后果,另一方面也便于定位问题,提高升序的可维护性。
那么我们如何发现异常呢?是不是需要程序员一条条编写检查代码呢?答案是否定的,而且用一句话就能解释,EAFP,懂的都懂,不懂的看下面。
It’s easier to ask for forgiveness than permission
EAFP带给Python一种很不一样的特质:把思考聚焦在程序的正常执行流上,进而保持思维流的连贯。当然这也得益于Python语言精心设计的Exception类层级。
Python中没有直接定义Interface这个概念,但是ABC(Abstract Base Class)充当了这一功能,使得程序员可以对现实世界的东西建模,定义语法和语义都严谨的一组方法,然后配合Python自带的isinstance和isubclass函数,可以在运行时灵活地对对象进行自省。
Goose Typing算是对Duck Typing的一种补充,允许适当且适量地使用isinstance,并且第二个参数必须是ABC而不是具体类型。
在一个菱形的继承关系中,有可能出现命名冲突的问题——互为兄弟节点的两个类各自有自己的方法实现。当出现这种情况时,每种语言都要有一套决议(Resolution)方案,Python的方案为mro,即Method Resolution Order。
mro存储在类的一个名为__mro__
的属性中,是一个元组。
super这个名字可能有些误导,会让人以为会返回当前类的父类。首先先摒弃掉这种望文生义的想法。其次,super的工作机制与mro紧密联系,具体来说,mro决定了在一个多继承关系中类的方法激活顺序,而是否被激活取决于方法的实现是否调用了super。如果调用了super,那么调用链将沿着mro继续;如果没有,调用链就结束。因此,super函数是协作式的。
Python中的f
字符串、format()
内置函数、str.format()
方法中都接受format_spec
作为参数。
f字符串中包含一种特殊的以开闭花括号(‘{
‘, ‘}
‘)为界的replacement field,形如{field_name:format_spec}
。
在format_spec中使用的记号称之为Format Specification Mini-Language。
用户自定义类可以实现__format__
方法来自定义自己的Format Specification Mini-Language,object类中的默认实现是返回str(my_object)
。
从语法上讲,在类的定义中必须实现以下2个方法:
__eq__(self, other: object)
__hash__(self)
从语义上讲,类的定义必须满足以下条件:
用户自定义类支持切片的必要条件是实现__getitem__
魔法方法,语义上也要满足。当执行切片时,__getitem__
的入参类型为slice
,且它是Python的内置类型。
slice
类型除了大家熟知的start
、stop
、stride
外,还有一个鲜为人知的方法,indices
,官方文档说明如下:
Assuming a sequence of length len, calculate the start and stop
indices, and the stride length of the extended slice described by
S. Out of bounds indices are clipped in a manner consistent with the
handling of normal slices.
说白了,某个slice
中的三个关键属性:start
、stop
、stride
,有可能缺省,有可能为负数,indices的作用就是根据序列的长度len
,把它们补齐,或者重新计算,使得其“完美”适配长度为len
的序列,比如原本stop
属性的值大于len
,那么新的stop
会等于len
,这个过程称之为归一化(Normalize)。
__dict__
属性查看。Qualified Name | Include | Reference |
---|---|---|
std::pair | <utility> | pair-cppreference |
Name | Type | Synopsis |
---|---|---|
first | T1 | pair的第一个成员变量 |
second | T2 | pair的第二个成员变量 |
Signature | Synopsis | Notes |
---|---|---|
pair<T1, T2> make_pair(const T1& t, const T2& u); | 用于构造的工具函数 |
Signature | Synopsis | Notes |
---|---|---|
iterator find(const Key& key); | 检索与key相等的元素 | Lookup |
Qualified Name | Include | Reference |
---|---|---|
std::deque | <deque> | deque-cppreference |
Signature | Synopsis | Notes |
---|---|---|
reference front(); | 获取队首元素 | |
reference back(); | 获取队尾元素 |
Signature | Synopsis | Notes |
---|---|---|
void push_front(const T& value); | 向队首压入元素 | |
void emplace_front(Args&&... args); | 向队首压入元素,与push_front所不同的是,直接在队列的内部地址上初始化数据,而无需经过一次拷贝或移动 | |
void push_back(const T& value); | 向队尾压入元素 | |
void emplace_back(Args&&... args); | 向队尾压入元素,与push_back不同的是,直接在队列的内部地址上初始化数据,而无需经过一次拷贝或者移动 | |
void pop_front(); | 从队首弹出元素 | |
void pop_back(); | 从队尾弹出元素 |
Qualified Name | Include | Reference |
---|---|---|
std::unordered_set | <unordered_set> | unordered_set-cppreference |
std::set |
Signature | Synopsis | Notes |
---|---|---|
std::pair<iterator, bool> insert(const value_type& value); | 插入元素 |
Qualified Name | Include | Reference |
---|---|---|
std::priority_queue | <queue> | priority_queue-cppreference |
Signature | Synopsis | Notes |
---|---|---|
const_reference top() const; | ||
void push(const value_type& value); | ||
void pop(); |