草庐IT

读编程与类型系统笔记06_函数类型的高级应用

躺柒 2023-03-28 原文

1. 装饰器模式

1.1. 扩展对象的行为,而不必修改对象的类

1.2. 装饰的对象可以执行其原始实现没有提供的功能

1.3. 优势

1.3.1. 支持单一职责原则

1.3.1.1. 每个类只应该承担一种职责

1.4. 经典实现

1.4.1. 一个IComponent接口

1.4.2. 一个具体实现,即ConcreteComponent

1.4.3. 使用额外行为来增强IComponent的Decorator

1.4.3.1. 例如:添加单例行为

1.4.4. 特点

1.4.4.1. 一个接口

1.4.4.1.1. 接口声明了多个方法,就无法使用一个函数类型来替代接口

1.4.4.2. 两个类

1.4.4.3. 每个类一个方法

1.4.4.3.1. 具体操作
1.4.4.3.2. 装饰器

1.5. 函数装饰器

1.5.1. 接口改为一个函数类型

1.5.1.1. 示例:该类型的函数不接受实参,返回一个Widget:() => Widget

1.5.2. 一个具体实现的类替换为简单函数

1.5.3. 一个新函数singletonDecorator()

1.5.3.1. 接受一个WidgetFactory类型的函数

1.5.3.2. 返回另外一个WidgetFactory类型的函数

1.5.3.3. 采用lambda实现

1.5.4. 特点

1.5.4.1. 一个函数类型

1.5.4.1.1. 工厂函数类型

1.5.4.2. 两个函数

1.5.4.2.1. 工厂函数
1.5.4.2.2. 装饰器函数

1.6. 闭包

1.6.1. lambda捕获

1.6.1.1. lambda内捕获的一个外部变量

1.6.2. 编程语言通过闭包来实现lambda捕获

1.6.3. 闭包记录了创建该函数时的环境

1.6.3.1. 可以在不同调用之间维护状态

1.6.4. lambda引用了函数的局部变量

1.6.4.1. 其生存期将大于创建它的函数

1.6.4.2. 函数的局部变量在调用函数时创建,在函数返回时销毁

1.6.5. 保留了其外层函数的一些状态信息的lambda

1.6.6. 只有存在高阶函数,闭包才有意义

1.6.6.1. 不能从一个函数中返回另一个函数,就不存在要捕获的环境

1.6.6.2. 所有函数都在全局作用域内,所以全局作用域就是它们的环境

1.6.6.2.1. 函数只能引用全局变量

1.6.7. 对象代表一组方法的某个状态

1.6.8. 闭包则代表捕获到某个状态的函数

2. 计数器

2.1. 全局计数器

2.1.1. 一个引用全局变量的简单函数

2.1.2. 缺点

2.1.2.1. 计数器的值没有被恰当封装

2.1.2.2. 不能使用计数器的两个独立的实例

2.2. 面向对象的计数器

2.2.1. 多个独立的计数器

2.3. 函数式计数器

2.3.1. 代码比面向对象版本的更加简洁

2.4. 可恢复的计数器

2.4.1. 可恢复的函数

2.4.1.1. 跟踪自己状态的函数,在被调用时,不会从头运行,而是从上一次返回时所在的状态恢复执行

2.4.2. 不使用关键字return来退出函数

2.4.3. 使用关键字yield

2.4.3.1. 必须把函数声明为一个生成器

2.4.3.2. 其返回类型必须是可迭代的迭代器

2.4.3.3. 在函数名称的前面加上星号来声明生成器

2.4.4. TypeScript语法

2.4.5. 生成器通过特殊语法来创建可恢复的函数

2.4.6. 生成器不是返回控制权,而是交出控制权

3. 异步

3.1. 按顺序运行代码可能导致不可接受的延迟

3.2. 回调

3.2.1. 作为实参提供给异步函数的一个函数

3.2.2. 也可以从异步函数那里收到实参

3.3. 异步执行模型

3.3.1. 线程

3.3.2. 事件循环

3.3.2.1. 使用一个队列

3.3.2.2. 异步函数将被加入队列

3.3.2.3. 它们自己也可以将其他函数排队

3.3.2.4. 只要队列不为空,队列中的第一个函数就将被取出来执行

3.3.2.5. 优点

3.3.2.5.1. I/O操作等待数据时让它们排队的效果很好
3.3.2.5.2. 不需要同步,因为所有代码在一个线程上运行

3.3.2.6. 缺点

3.3.2.6.1. 对于运行时间长,但是不能被拆分为多个操作的任务,效果不好
3.3.2.6.2. CPU密集的操作会造成阻塞
3.3.2.6.2.1. CPU密集的操作(如复杂计算)不能被排队
3.3.2.6.2.2. 需要CPU周期
3.3.2.6.2.3. 没有等待数据

3.4. 简化异步代码

3.4.1. promise

3.4.1.1. 将来某个时刻可用的值的一个代理

3.4.1.2. 在生成该值的代码运行之前,其他代码可以使用该promise设置在该值可用后如何处理该值,在发生错误时如何处理,甚至取消将来的执行

3.4.1.3. 让代码的可读性相比使用回调时更好

3.4.1.4. 状态

3.4.1.4.1. 等待(pending)
3.4.1.4.1.1. 已被创建,但还没有完成
3.4.1.4.2. 完成(settled)
3.4.1.4.2.1. 已经调用了,并提供了一个值,此时将调用continuation
3.4.1.4.3. 拒绝(rejected)
3.4.1.4.3.1. 调用reject()或者抛出错误

3.4.1.4.3.1.1. 当前的promise会被拒绝

3.4.1.4.3.1.2. 通过then()链接到该promise的其他所有promise都会被拒绝

3.4.1.5. 组合promise

3.4.1.5.1. Promise.all()
3.4.1.5.1.1. 一组promise作为实参
3.4.1.5.1.2. 返回当提供的所有promise都完成后完成的一个promise
3.4.1.5.2. Promise.race()
3.4.1.5.2.1. 一组promise作为实参
3.4.1.5.2.2. 返回当提供的任何一个promise完成时完成的一个promise

3.4.2. continuation

3.4.2.1. 在promise的结果可用后调用的函数

3.4.2.2. 并非必须返回一个promise

3.4.2.2.1. 不是总会链接异步函数
3.4.2.2.2. 可以同步执行
3.4.2.2.3. 自动转换为Promise

3.4.2.3. 每个continuation放到一个单独的函数中,并通过then()把它们链接起来

3.4.3. 函数promise提供给我们某个类型T的值,以及指定从T到其他某个类型U的函数((value: T)=> U)的能力,当承诺被履行,我们得到了值以后,将调用这个函数(它就是continuation)

3.4.4. JavaScript(及TypeScript)采用Promise类型实现

3.4.5. C#采用Task实现

3.4.6. JAVA采用CompletableFuture实现

3.4.7. async/await

3.4.7.1. 代码的可读性更好

3.4.7.1.1. 异步代码读起来类似于同步代码

3.4.7.2. 把所有代码写到一个函数中,每当调用另外一个返回promise的函数,就等待(await)其结果,然后在得到结果后继续执行

3.4.7.3. 异常将从await调用抛出,可在try/catch语句中捕获

3.4.7.4. 不使用then()提供continuation

3.4.7.5. 语法糖

有关读编程与类型系统笔记06_函数类型的高级应用的更多相关文章

  1. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  2. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  3. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  4. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  10. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

随机推荐