Ruby 中的闭包-代码块
看了一片文章https://ruby-china.org/topics/38385讲closure的。
写下一些感想:
闭包就是 一个函数能够记住和存取它的lexical作用域,即使这个函数是在它的lexical作用域的外面执行。
当一个函数被写出来时,这个函数的closure就已经确定了。
javascript中有闭包的概念:https://www.cnblogs.com/chentianwei/p/9739714.html
Ruby中的关键字定义def是没有闭包的。它创建一个封闭的作用域。
但是Ruby有闭包的概念这就是--代码块。
a = 100 define_method :add_a do
a = a + 1
end puts add_a # => 101
puts add_a # => 102
puts add_a # => 103
这个例子使用了define_method方法搭配一个代码块来定义方法。我们就可以访问外部的作用域的局部变量a。
Ruby就是使用代码块来表示闭包的。
可以参考《Ruby元编程》相关章节的例子:
def my_method
x = "GoodBye"
puts yield("cruel")
end x = "Hello"
my_method do |y|
"#{x}, #{y} world!"
end
代码块绑定了变量x。即外部作用域的变量跟着代码块一起走!
代码块的意义:
在Ruby的开源世界,代码块无处不在:
1.容错涉及:
Ruby承袭于Lisp,代码块的运行会自动返回最后一条语句或者表达式的值,于是有些库也考虑到了用代码块来进行容错处理。
例子:
> hash = {}
> value = hash.fetch('a') { 'default value' }
=> "default value"
因为hash是空的,没有"a", 所以会返回代码块中的字符串,如果不提供代码块,就会报错❌。
2. DSL
3. 蹩脚的函数
代码块可以看作是一个蹩脚的函数,虽然一般情况下可以作为某个方法的回调,但在Ruby中代码块需要依赖其他机制来存在,而不是JS中的函数那样独立存在。
当使用代码块来定义一个匿名函数时,需要搭配lambda关键字或Proc类来实现。
> c = lambda() {}
=> #<Proc:0x00007ff47b8546a8@(irb):6 (lambda)>
> c.class
=> Proc
> (lambda() { 'hello' }).call
=> "hello"
> (lambda() { 'hello' })[]
=> "hello"
> (Proc.new { 'hello' }).call
=> "hello"
> (Proc.new { 'hello' })[]
=> "hello"
x = "tom"
(lambda() {"Hello,#{x}"}).call
以上都是常用的定义匿名函数的方式,本质上它们都是Proc类的实例,需要显式地利用Proc#call方法或者语法糖[]来调用它们。
总结:
这篇文章介绍了Ruby中的闭包概念, 它和封闭作用域的方法(使用def关键字定义的方法)有什么不同。
⚠️ Ruby中定义了三个地方为封闭的作用领域(对应三个关键字):
- 类定义 class
- 模块定义 module
- 方法def
区别于一般的方法,闭包在Ruby中以代码块的形式出现,它在Ruby世界中几乎无处不在,充当了一等公民。这种区分,不仅使我们的Ruby代码更加优雅,增添了可读性,还使得我们的编码过程更加简单。
Ruby 中的闭包-代码块的更多相关文章
- 2.java中c#中statc 静态调用不同之处、c#的静态构造函数和java中的构造代码块、静态代码块
1.java和c#静态成员调用的不同之处 static 表示静态的,也就是共享资源,它是在类加载的时候就创建了 java中 可以通过实例来调用,也可以通过类名.成员名来调用,但是一般最好使用类名. ...
- Java中的构造代码块
代码块 ----a静态代码块 ----b构造代码块 ----c普通代码块 执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. a.静态代码块: 静态代码块 ...
- Gradle中的buildScript代码块
在编写Gradle脚本的时候,在build.gradle文件中经常看到这样的代码: build.gradle 1 2 3 4 5 6 7 8 9 buildScript { repositories ...
- java中静态的代码块,静态变量,静态方法
简单了解一下java虚拟机--jvm几个内存区域: 方法区:在java的虚拟机中有一块专门用来存放已经加载的类信息.常量.静态变量以及方法代码的内存区域, 常量池:常量池是方法区的一部分,主要用来存放 ...
- Java中的局部代码块、构造代码块、静态代码块
局部代码块: 作用:控制变量的生命周期: 在程序中,当我们已经使用完 x 后,并且在接下来的代码中,不会再用到x,那么就没必要让x 在内存中占用空间了,这用情况下,可以使用 局部代码块,将x及其所设计 ...
- [转] Gradle中的buildScript代码块
PS: 在build script中的task apply plugin: 'spring-boot' 需要 classpath("org.springframework.boot:spri ...
- java中的静态代码块等执行顺序
http://www.cnblogs.com/naruto469/p/3608459.html public class Print { 2 3 public Print(String s){ 4 S ...
- java中的static代码块为什么只执行一次
原因在最后,这是其中的一个小例子. 如: SessionFactory负责保存和使用所有配置信息,消耗内存资源非常大 所以一个web项目要保证只创建一个SessionFactory 那么在使用hibe ...
- 5.1JAVA基础复习——JAVA中的静态代码块、构造代码块、构造函数、局部代码块区别
构造代码块: 在类中定义可以给所有对象进行初始化.局部代码块: 在方法中定义属性的生命周期.静态代码块: 在类中定义用于给类调用时属性的初始化 构造函数与构造代码块的区别: 构造函数是给对应的对象进行 ...
随机推荐
- 非常好用的vue数字滚动插件vue-countTo
参考链接:https://blog.csdn.net/gaoxin666/article/details/84635056
- Go 采用 time.After 实现超时控制
场景: 假设业务中需调用服务接口A,要求超时时间为5秒,那么如何优雅.简洁的实现呢? 我们可以采用select+time.After的方式,十分简单适用的实现. time.After()表示time. ...
- Linux多线程编程 - sleep 和 pthread_cond_timedwait
#include <stdio.h> #include <stdlib.h> int flag = 1; void * thr_fn(void * arg) { while ...
- Find Duplicate File in System
Given a list of directory info including directory path, and all the files with contents in this dir ...
- 【Python】【demo实验9】【练习实例】【三数排序】
原题: 输入三个整数x,y,z,请把这三个数由小到大输出. 我的解法: #!/usr/bin/python # encoding=utf-8 # -*- coding: UTF-8 -*- # 输入三 ...
- 2019-07-30 C#基础知识学习
继承和多态 接口与抽象类的区别:1.在接口中仅能定义成员,但是不能有具体的实现:抽象类除了抽象成员以外,其他成员有具体的实现.2.在接口中不能声明字段,并且不能声明任何私有成员,成员不能包含任何修饰符 ...
- django ajax MTV与MVC 多对多创建方式
MTV与MVC MTV模型(django): M:模型层(models.py) T:templates V:views MVC模型: M:模型层(models.py) V:视图层(views.py) ...
- MySQL-复杂查询及条件-起别名-多表查询-04
目录 基本查询语句及方法 测试数据创建 创建数据库与表 插入表记录数据 数据展示 常见结果排版 另一种结果排版 \G 简单查询语句的书写与执行顺序 查询语句书写 执行顺序 科普-- 起别名 写法 可以 ...
- mysql 8.x 登陆提示 Access denied for user 'root'@'localhost' (using password: YES)
第一步:修改 /etc/mysql/my.cnf. 在[mysql]下添加skip-grant-table:重启. 第二步:通过mysql命令登陆: flush privileges; use mys ...
- LinqToSQL3
Lambda Lambda表达式和匿名方法很相似,但Lambda表达式比匿名方法更灵活,并且语法比匿名方法更简洁. 在LINQ中可以使用Lambda表达式创建委托,这些委托将稍后执行查询时被调用. L ...