ruby迭代map的简洁写法实现原理分析

简便方法的用法

现有一个字符串列表,需要对其中的每个字符串执行转换大写操作,我们可以用一个简便写法来完成。

代码如下:

name_list = ["chareice", "angel"]
name_list.map(&:upcase)
# => ["CHAREICE", "ANGEL"]

这个写法等同于

代码如下:

name_list.map do {|name| name.upcase}

简便写法带来的是很明显的效率提升,可是这看似魔术一般的参数,背后的原理是怎样的呢?

&符号

如果把上面方法调用的&符号去掉,可以很明显得看到,是把:upcase这个符号传到方法中,作为方法的参数。

实际上,&符号代表的是块转变为Proc(block-to-proc conversion)。我们看下面的一个例子。

代码如下:

def capture_block(&block)
  block.call
end

capture_block { puts "我有一只小毛驴,我从来也不骑。" }
# => 我有一只小毛驴,我从来也不骑。

我们运行capture_block函数,给它传递一个代码块,代码块会经&符号的转换变为一个Proc对象传递到函数中,在上面的例子中就是block变量。如果我们输出一下block的class,输出的结果会是Proc。

你也可以将一个Proc对象传递给capture_block来代替代码块.

代码如下:

p = Proc.new { puts "又给一只小毛驴" }
capture_block(&p)
# => 又给一只小毛驴

这里看来&符号是多余的,完全可以去掉&,运行的结果也是一样。

&符号做了什么?

以capture_block(&p)调用为例。

1.触发p的to_proc方法。
2.告诉Ruby解释器,将to_proc方法返回的结果当做本次函数调用的block。

如果同时使用了&符号和传入了block给一个函数,Ruby会报错。

代码如下:

capture_block(&p) { puts "传给一个block" }
#=>SyntaxError: (irb):30: both block arg and actual block given

所以将一个Proc对象传给&符号,它会调用Proc对象的to_proc方法,返回它自己,然后把它当做方法调用的block传递给方法。

&:upcase是什么?

知道了&符号的作用后,我们可以看到,&:upcase是先调用了:upcase对象的to_proc方法。

:upcase的to_proc方法实现如下:

代码如下:

class Symbol
  def to_proc
    Proc.new {|obj| obj.send(self) }
  end
end

这下结果就很清楚了,Symbol#to_proc会返回一个带参数的Proc对象,Proc对象所做的是为使用这个Proc对象的对象发送调用名字为该符号的方法。

(0)

相关推荐

  • Ruby Gems更换淘宝源方法

    最近由于要做课设,所以昨天装了个 Windows,感觉闲的没事干,就想装个 Ruby 玩玩. 官方的 Rubygems 源由于有些资源放在 Amazon S3 上面,所以有时会抽风,在 Linux 下我用 proxychains gem install xxx 实现了指定程序实行 Shadowsocks 代理,但是 Windows 下不方便全局代理,所以就考虑换国内的淘宝源了. 之前换过一两次,但是由于只是两行命令而又不经常使用,所以就忘了,这次把它记录下来. 复制代码 代码如下: # 删除默认

  • Ruby中访问SQL Server数据库的配置实例

    因为工作需要,要分析存放在SQL Server上的数据,所以不得不研究一下如何使用Ruby访问SQL Server,发现其实还是很简单的: 安装FreeTDS 下载FreeTDS源代码 解压编译安装: 复制代码 代码如下: ./configure --prefix=/usr/local/freetds && make && sudo make install 安装Tiny_TDS Tiny_TDS,安装和使用非常简单,推荐使用: 复制代码 代码如下: sudo gem in

  • 举例理解Ruby on Rails的页面缓存机制

    有了页面缓存,Rails 就可以不再介入.在某种程度上,这是件好事,因为您的确可以获得优秀的性能.Rails 只需创建 HTML 页面,将其放入目录,之后,就可以置之于脑后.从那时起,就由应用服务器管理这些页面,且页面进入应用服务器无需任何循环.从性能的角度而言,页面缓存真是天赐之福. 我也钟爱页面缓存,Rails 使之简单利落.只需使用一行代码就可以启用缓存.如果再加入一些代码,就能通过简单地删除文件操作或使用 Rails 较高层的 API 终止缓存.这里存在一个问题.并不是每个网站都能使用页

  • ruby迭代map的简洁写法实现原理分析

    简便方法的用法 现有一个字符串列表,需要对其中的每个字符串执行转换大写操作,我们可以用一个简便写法来完成. 复制代码 代码如下: name_list = ["chareice", "angel"] name_list.map(&:upcase) # => ["CHAREICE", "ANGEL"] 这个写法等同于 复制代码 代码如下: name_list.map do {|name| name.upcase} 简

  • java迭代器原理及迭代map的四种方式

    目录 迭代器原理: 什么是迭代器,使用迭代器的好处? 迭代器怎么实现的? 迭代器的陷阱? 为什么会产生这样的错误? 遍历map的四种方式 迭代器原理: 什么是迭代器,使用迭代器的好处? 迭代器就是用来遍历集合中对象的东西,也就是说,对于集合,我们不像对原始数组那样通过直接访问元素来迭代的,而是通过迭代器来遍历对象.这么做的好处是将对于集合类型的遍历行为与被遍历集合对象分离,这样以来,就不需要关心该集合类型的具体实现是怎么样的.只要获取这个集合对象的迭代器便可以遍历这个集合中的对象.而像遍历对象顺

  • MyBatis传入集合 list 数组 map参数的写法

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合.foreach元素的属性主要有item,index,collection,open,separator,close.item表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collection属性

  • python字典通过值反查键的实现(简洁写法)

    通过键查值比较容易,通过值反查键就稍微麻烦点,这里给大家提供点思路. 由于值是可以重复的,所以分成两种情况给大家展示: 第一种是值唯一的情况直接构造列表,通过value的索引取对应的key. 第二种是值不唯一的情况,需要通过for遍历出所有的索引然后查出所有对应的key. 如果你需要打印所有满足查询值所对应的key,选第二种: 如果你只需要打印首次出现查询值所对应的key,选第一种. 代码如下: #假如值唯一 mydisc = {'key1':'123', 'key2':'234', 'key3

  • Java LinkedHashMap 底层实现原理分析

    在实现上,LinkedHashMap很多方法直接继承自HashMap,仅为维护双向链表覆写了部分方法.所以,要看懂 LinkedHashMap 的源码,需要先看懂 HashMap 的源码. 默认情况下,LinkedHashMap的迭代顺序是按照插入节点的顺序.也可以通过改变accessOrder参数的值,使得其遍历顺序按照访问顺序输出. 这里我们只讨论LinkedHashMap和HashMap的不同之处,LinkedHashMap的其他操作和特性具体请参考HashMap 我们先来看下两者的区别:

  • Java8 HashMap的实现原理分析

    前言:Java8之后新增挺多新东西,在网上找了些相关资料,关于HashMap在自己被血虐之后痛定思痛决定整理一下相关知识方便自己看.图和有些内容参考的这个文章:http://www.jb51.net/article/80446.htm HashMap的存储结构如图:一个桶(bucket)上的节点多于8个则存储结构是红黑树,小于8个是单向链表. 1:HashMap的一些属性 public class HashMap<k,v> extends AbstractMap<k,v> impl

  • Java HashMap实现原理分析(一)

    从本文开始,介绍一下最常用的一个集合对象HashMap,HashMap存储的是键值对,本文采用的基于JDK11的源码实现. 一般大家都知道HashMap是通过put操作把一组键值对(key和value)存储到HashMap中,然后可以通过get(key)去获取key对应的value.而最重要的这两个过程是怎么实现的呢?下面我们就来对put和get这两个过程做一个分析. HashMap基本工作原理 下面先看一段源码: /** * The table, initialized on first us

  • python 如何引入协程和原理分析

    相关概念 并发:指一个时间段内,有几个程序在同一个cpu上运行,但是任意时刻只有一个程序在cpu上运行.比如说在一秒内cpu切换了100个进程,就可以认为cpu的并发是100. 并行:值任意时刻点上,有多个程序同时运行在cpu上,可以理解为多个cpu,每个cpu独立运行自己程序,互不干扰.并行数量和cpu数量是一致的. 我们平时常说的高并发而不是高并行,是因为cpu的数量是有限的,不可以增加. 形象的理解:cpu对应一个人,程序对应喝茶,人要喝茶需要四个步骤(可以对应程序需要开启四个线程):1烧

  • Android ANR原理分析

    目录 卡顿原理 卡顿监控 ANR原理 卡顿原理 主线程有耗时操作会导致卡顿,卡顿超过阀值,触发ANR. 应用进程启动时候,Zygote会反射调用ActivityThread的main方法,启动loop循环. ActivityThread(api29) public static void main(String[] args) { Looper.prepareMainLooper(); ... Looper.loop(); throw new RuntimeException("Main thr

  • SpringCloud Gateway 路由配置定位原理分析

    环境:springcloud Hoxton.SR11 本节主要了解系统中的谓词与配置的路由信息是如何进行初始化关联生成路由对象的.每个谓词工厂中的Config对象又是如何被解析配置的. 所有的谓词工厂中的Config中属性值是如何被配置的. 在SpringCloud Gateway中的所有谓词工厂如下: 命名规则:XxxRoutePredicateFactory.所有的这些谓词工厂都是如下的继承关系 public class MethodRoutePredicateFactory extends

随机推荐