From 8fdca49e1d63db1075a23958ff23189818a49d6c Mon Sep 17 00:00:00 2001
From: muqiuhan
|
C++20没有提供关键的 ranges::to<container>函数,导致demo中还需要额外封装并手写for_each来写入数据,等到C++23实装了该函数,split的实现会比现在简洁优雅的多,真正做到方便泛用、无需封装:
auto&& strCont = str |
/// Inserts a new element at the end of the vector, right after its current last element. This new element is constructed in place using args as the arguments for its constructor. |
push_back 会构造一个临时对象,这个临时对象会被拷贝或者移入到容器中,然而 emplace_back 会直接根据传入的参数在容器的适当位置进行构造而避免拷贝或者移动。
传统观点认为 push_back 会构造一个临时对象,这个临时对象会被移入到 v 中,然而 emplace_back 会直接根据传入的参数在适当位置进行构造而避免拷贝或者移动。从标准库代码的实现角度来说这是对的,但是对于提供了优化的编译器来讲,上面示例中最后两行表达式生成的代码其实没有区别。
真正的区别在于,emplace_back 更加强大,它可以调用任何类型的(只要存在)构造函数。而 push_back 会更加严谨,它只调用隐式构造函数。隐式构造函数被认为是安全的。如果能够通过对象 T 隐式构造对象 U,就认为 U 能够完整包含 T 的所有内容,这样将 T 传递给 U 通常是安全的。正确使用隐式构造的例子是用 std::uint32_t 对象构造 std::uint64_t 对象,错误使用隐式构造的例子是用 double 构造 std::uint8_t。
如果想要调用显示构造函数,那么就调用 emplace_back。如果只希望调用隐式构造函数,那么请使用更加安全的 push_back:
std::vector<std::unique_ptr<T>> v; |
std::unique_ptr<T> 包含了显示构造函数通过 T* 进行构造。因为 emplace_back 能够调用显示构造函数,所以传递一个裸指针并不会产生编译错误。然而,当 v 超出了作用域,std::unique_ptr<T> 的析构函数会尝试 delete 类型 T* 的指针,而类型 T* 的指针并不是通过 new 来分配的,因为它保存的是栈对象的地址,因此 delete 行为是未定义的。
C++ 的 traits 技术,是一种约定俗称的技术方案,用来为同一类数据(包括自定义数据类型和内置数据类型)提供统一的类型名(traits),这样可以统一的操作函数,例如 advance(), swap(), encode()/decode() 等。
- -例如,拥有义类型Foo, Bar,以及编译器自带类型 int, double, string,我们想要为这些不同的类型提供统一的编码函数 decode() 。
-除了使用 trait 技术之外,函数重载和模板函数 + 内置字段也可以实现,前者每增加一种数据类型就需要重新实现一个函数,而同一类数据(int, unsinged int)可以使用同样的编码方法。我们想要的是针对同一种数据类型,只编写一个函数。后者对于系统自定义变量 int, double 而言,是无法在其内部定义 type 的。
-traits 技术的关键在于,使用另外的模板类 type_traits 来保存不同数据类型的 type,这样就可以兼容自定义数据类型和内置数据类型:
-// 定义数据 type 类 |
对于自定义类型,在类内部定义 type,然后在 traits 类中定义同样的 type:
-// 自定义数据类型 |
对于内置数据类型,使用模板类的特化为自定义类型生成独有的 type_traits:
-// 内置数据类型 |
这样就可以为不同数据类型生成统一的模板函数
-// 统一的编码函数 |
总结
-G-Machine 是一种通过图规约来对函数式语言程序求值的抽象架构。
与组合子规约不同,组合子规约的control是从表达式图本身动态导出的,而G-Machine是由通过编译Application表达式导出的指令序列指定的。
FP的程序基本上都可以用一个表达式的图表示,图计算机就是对这个图求值的机器,总的说来对图的求值是一个不停合并图上的节点生产新节点的过程。
+例如:
+let x = 2 + 3 in |
先计算出5,然后创建一个新的节点 5 * 5,然后再对这个节点求值,于是求值过程中就产生了很多临时的节点,这些中间节点也被叫做是 spine,求值过程是沿着 spine 进行的。
但是这样就产生了很多额外的开销,lambda lifting 里提到:可以把程序里,很多捕捉了外围绑定的闭包函数中的这些绑定,转换成函数的参数,从而消除闭包,得到的这个函数就可以自由脱离作用域,被静态的编译到机器码里。这些被 float out 的函数也叫 supercombinator.
+在上面的代码中,如果不创建新的节点,顺序计算完了第一个 x,第二个 x 还会再被算一遍。
Spineless reduction 的概念:只有当面临需要重复计算的情况时,才去创建节点,不然就一路顺序算下去
+ +]]>G-Machine 是一种通过图规约来对函数式语言程序求值的抽象架构。
与组合子规约不同,组合子规约的control是从表达式图本身动态导出的,而G-Machine是由通过编译Application表达式导出的指令序列指定的。
FP的程序基本上都可以用一个表达式的图表示,图计算机就是对这个图求值的机器,总的说来对图的求值是一个不停合并图上的节点生产新节点的过程。
-例如:
-let x = 2 + 3 in |
先计算出5,然后创建一个新的节点 5 * 5,然后再对这个节点求值,于是求值过程中就产生了很多临时的节点,这些中间节点也被叫做是 spine,求值过程是沿着 spine 进行的。
但是这样就产生了很多额外的开销,lambda lifting 里提到:可以把程序里,很多捕捉了外围绑定的闭包函数中的这些绑定,转换成函数的参数,从而消除闭包,得到的这个函数就可以自由脱离作用域,被静态的编译到机器码里。这些被 float out 的函数也叫 supercombinator.
-在上面的代码中,如果不创建新的节点,顺序计算完了第一个 x,第二个 x 还会再被算一遍。
Spineless reduction 的概念:只有当面临需要重复计算的情况时,才去创建节点,不然就一路顺序算下去
- -]]>“世人皆以痛楚、孤独、悲伤为大境界,以为这就是深邃的人生,殊不知快乐才是人生的真谛。一个人获取快乐的能力才是真正有用的能力。伤春悲秋、离愁别绪太容易了,读几首诗词即可,但获取欢乐太难了非大丈夫不可为之。”
]]>一个人的世界很容易出现信息茧房,要不断的和人交流,把很多想法说出来,接收一切评论,不然会在长期的不分正确错误的信息堆叠中出现一团巨大的闭塞性的知识,这很不利于我们快乐的活下去。
-接收到的评论不必急于改变,先存起来,让它们陪着你跟着时间走,路上会慢慢的和其他的事情连结起来,这样就能择其善者而从之,其不善者而改之了。
-和我一样处在青少年阶段的宝宝们应当早日从这喧扰的世界冷静下来,让脑子里满是憧憬和情爱的灵魂得到一丝陈酿,理性点抬头看看世界上方的二氧化碳,自己晃晃头打破能回到最初的样子再重来的梦。
-爱你们噢。
+独处的世界很容易出现信息茧房,要不断的和人交流,把很多想法说出来,接收一切评论,不然会在长期的不分正确错误的信息堆叠中出现一团巨大的闭塞性的知识,这很不利于快乐的活下去。
+接收到的评论不必急于改变,先存起来,让它们陪着自己,跟着时间走,路上会慢慢的和其他的事情连结起来,这样就能择其善者而从之,其不善者而改之了。
+应当早日从这喧扰的世界冷静下来,让脑子里满是憧憬和情爱的灵魂得到一丝陈酿,理性点抬头看看世界上方的二氧化碳,自己晃晃头打破能回到最初的样子再重来的梦。
+爱你们。
]]>以下是事件风暴及相关领域驱动设计中的一些核心概念和知识点:
+1. 领域(Domain):指的是业务相关知识的集合,可以进一步划分为子域。
2. 子域(Subdomain):是领域的一部分,可以是核心域、支撑域或通用域。
3. 核心域(Core Domain):指领域中最核心的部分,通常对应企业的核心业务。
4. 通用语言(Ubiquitous Language):团队所有成员使用的一种语言,用于确保业务和软件之间的沟通一致性。
5. 限界上下文(Bounded Context):定义了一组规则和协议,用于明确领域模型的适用范围。
6. 实体(Entity):具有唯一标识和生命周期的领域对象。
7. 值对象(Value Object):描述了某种特性或属性的对象,没有概念标识。
8. 聚合(Aggregate):一组相关对象的集合,由一个聚合根(Aggregate Root)统一管理。
9. 领域事件(Domain Event):领域中发生的重要事件,可以用于通知其他领域对象或跨限界上下文进行解耦和协作。
10. 命令(Command):表示要执行的操作,通常与事件一一对应。
11. 读模型(Read Model):为了优化读取操作而设计的模型,可能与写模型不同。
12. 决策命令(Decision Command):在事件风暴中,直接导致事件发生的命令。
13. 战略设计(Strategic Design):高层次的抽象和归类,包括理清上下文和子域的划分。
14. 战术设计(Tactical Design):对特定上下文下的模型进行详细设计,包括聚合、实体和值对象。
15. 贫血模型(Anemic Domain Model):领域对象只有属性及其getter/setter方法的纯数据类,业务逻辑通过服务实现。
16. 充血模型(Rich Domain Model):领域对象包含业务逻辑,每个对象都是活跃的。
17. 资源库(Repository):用于检索和持久化领域对象的机制。
18. 服务(Service):在模型中独立的操作,可以是领域服务或应用服务。
19. 固定规则(Invariant):为设计元素做出的断言,必须一直保持为真。
事件风暴通常包括以下步骤:
+input事件监听器来捕获用户的输入变化。以下是一个简单的防抖函数示例:
+function debounce(func, wait) { |
假设你有一个输入框用于搜索患者:
+<script> |
通过这种方式,你可以实现一个高效的实时搜索功能,既能保证用户体验,又能减少服务器的负担。
+]]>主要的作用如下:
+其具有以下特性:
+用 F# 来描述,以订单管理为例,大概写一下:
+type OrderStatus = |
在这个例子中,Order 是聚合根,它通过 AddItem 方法来添加订单项,保证每个订单项符合业务规则。同时,聚合根 Order 还负责订单状态的管理,例如通过 ChangeStatus 方法来更新订单状态。OrderItem 是聚合内的一个实体,表示订单项,它通过 GetTotalPrice 方法来计算每个订单项的总价。外部系统只能通过 Order 聚合根来访问和操作订单项,而不能直接访问或修改 OrderItem