美文网首页RubyRuby on Rails程序员
ruby proc/lambda/method/block

ruby proc/lambda/method/block

作者: 程序员小哥哥 | 来源:发表于2017-10-14 17:31 被阅读51次

一:proc / lambda

1.让我们分别以proc和lambda两种方式来定义代码块

2.2.2 :001 > a = proc { |x| x }
 => #<Proc:0x007fe62c31d610@(irb):1>
2.2.2 :002 > a.call(2)
 => 2
2.2.2 :003 > b = lambda { |x| x }
 => #<Proc:0x007fe62c26fc68@(irb):3 (lambda)>
2.2.2 :004 > b.call(3)
 => 3

2.proc和lambda有什么区别呢

(1)proc是一个代码块,而lambda更像一个方法

2.2.2 :005 > a.call
 => nil
2.2.2 :006 > b.call
ArgumentError: wrong number of arguments (0 for 1)
    from (irb):3:in `block in irb_binding'
    from (irb):6:in `call'
    from (irb):6
    from /Users/tnt29/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'

todo: proc不传递任何参数也是可以的,返回nil,而lambda不传递参数就会报错
(2)

2.2.2 :007 > def method_a
2.2.2 :008?>   a = proc { return 3 }
2.2.2 :009?>   a.call
2.2.2 :010?>   4
2.2.2 :011?>   end
 => :method_a
2.2.2 :012 > method_a
 => 3

todo: 在method_a这个方法内部,proc做为整个方法体直接返回了

2.2.2 :013 > def method_b
2.2.2 :014?>   b = lambda { return 5 }
2.2.2 :015?>   b.call
2.2.2 :016?>   6
2.2.2 :017?>   end
 => :method_b
2.2.2 :018 > method_b
 => 6

todo: lambda把方法内都执行完毕了

总结:proc和lambda最主要的区别是:
lambda的行为和传统意义的ruby的method方法的性质的是一致的,因为上面无论是参数的区别还是返回值的区别,都是和一个正常的函数保持一致的。
而proc严格意义上是一个代码块,改变当前作用的上下文的解释顺序的

二:method / block

如何将一个方法做为参数传递呢?

2.2.2 :019 > method(:method_a).call
 => 3

比如面试官为了考验你对代码块的理解给你出了一个面试题,你怎么定义一个方法来实现计数器
实现代码如下:

2.2.2 :021 >   def count
2.2.2 :022?>   a = 0
2.2.2 :023?>   proc { a+=1 }
2.2.2 :024?>   end
 => :count
2.2.2 :025 > x = count
 => #<Proc:0x007fe62be06eb0@(irb):23>
2.2.2 :026 > x.call
 => 1
2.2.2 :027 > x.call
 => 2
2.2.2 :028 > x.call
 => 3
2.2.2 :029 > x.call
 => 4
2.2.2 :030 >

这是个什么原理呢?
因为代码块是可以保留它所在方法的作用域的,当然也就代表保留了上下文作用域的变量。

其实在ruby中有一个方法叫binding是返回作用域的

2.2.2 :031 >   def hello
2.2.2 :032?>   y = 10
2.2.2 :033?>   end
 => :hello
2.2.2 :034 > hello
 => 10
2.2.2 :035 > y
NameError: undefined local variable or method `y' for main:Object
    from (irb):35
    from /Users/tnt29/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'

我们加上binding试一下

2.2.2 :063 > def hello
2.2.2 :064?>   y = 11
2.2.2 :065?>   binding
2.2.2 :066?>   end
 => :hello
2.2.2 :067 > m = hello
 => #<Binding:0x007fe62d0de448>
2.2.2 :068 > m.eval('y')
 => 11

binding可以获得当前作用域内部的变量,DSL中经常用到。

最后再说说block,我们经常遇到,就是do.. end
代码接受外部代码块有以下两种:

#命名代码块
2.2.2 :001 > def method_c &block
2.2.2 :002?>   block.call
2.2.2 :003?>   end
 => :method_c
2.2.2 :004 > method_c { 9 }
 => 9
#匿名代码块
2.2.2 :005 > def method_d
2.2.2 :006?>   yield
2.2.2 :007?>   end
 => :method_d
2.2.2 :008 > method_d { 10 }
 => 10

这两种方法的性能如何呢,用ruby内置的Benchmark模块来看下两个的运行时间
我们执行100万次

2.2.2 :012 > require 'benchmark'
 => false
2.2.2 :013 > Benchmark.realtime { 1_000_000.times { method_c { 9 } } }
 => 0.7558612880529836
2.2.2 :014 > Benchmark.realtime { 1_000_000.times { method_d { 9 } } }
 => 0.1121725169941783

这里会发现0.75秒(命名代码块) 第二个0.1秒(匿名代码块)
匿名代码块 效率远远高于命名代码块
所以在开发中我们尽量选择后者

相关文章

  • ruby proc/lambda/method/block

    一:proc / lambda 1.让我们分别以proc和lambda两种方式来定义代码块 2.proc和lamb...

  • Ruby block | lambda | Proc | yie

    据说每个面试ruby的公司都会问这个问题。 block 依旧是从代码直接开始 上面两个用的是Array的sort函...

  • ruby Method proc lambda 和闭包

    Proc和Lambda的区别,主要是: Proc和Lambda都是对象,而Block不是 参数列表中最多只能有一个...

  • Ruby中Proc,Lambda

    Ruby中的 Proc 和 Lambda 有些类似 high-order function。Proc 和 Lamb...

  • block, proc, lambda

    &:to_i是一个block,block不能独立存在,同时你也没有办法直接存储或传递它,必须把block挂在某个方...

  • [转]浅谈Ruby中的block, proc, lambda,

    本文主要介绍了ruby开发中的比较容易混淆的几个概念,并以简单示例的形式展现他们之间的区别,明白了这些区别之后,在...

  • Block、Proc 与 Lambda的区别

    Ruby的Block块是它的关键特色之一,用块能够写出简明且高度可重用的算法。我们也会经常用到,例如:produc...

  • ruby 方法调用中的*和&

    在ruby方法定义、调用中,*可以把数组转化为参数,&可以把Proc或lambda转化为块,在开发中可以起到很好的...

  • 如何进行代码块打包 && proc vs la

    proc和lambda的对比: proc和lambda都是代码块打包的工具不同之处在于:proc对参数的自适应性,...

  • Day7 读书笔记&心得体会

    一、读书笔记回顾昨天的收获:什么是block、proc? block和proc是两种不同的东西, block有形无...

网友评论

    本文标题:ruby proc/lambda/method/block

    本文链接:https://www.haomeiwen.com/subject/hsqfuxtx.html