千家信息网

Ruby的block怎么使用

发表于:2025-02-06 作者:千家信息网编辑
千家信息网最后更新 2025年02月06日,这篇文章主要介绍"Ruby的block怎么使用"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"Ruby的block怎么使用"文章能帮助大家解决问题。1. 块(b
千家信息网最后更新 2025年02月06日Ruby的block怎么使用

这篇文章主要介绍"Ruby的block怎么使用"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"Ruby的block怎么使用"文章能帮助大家解决问题。

1. 块(block)是一段「半自由」的代码,其形在方法外,而魂归方法里。

块(block)代码由{...}或do...end界定而成。

   [1, 2, 3].each{|i| i + 1}

块(block)代码不能被单独调用,只能依附于方法,所以称其为魂归方法里。

2. 块(block)魂归自身,获得完全自由的唯一方法就是,让其对象化。

魂归自身,意味着,它完全自由了,可被单独调用了

  Proc.new{ puts "hello"}  proc{ puts  "hello"}  proc{|msg| puts "hello #{msg}"}    lambda{puts "hello"}  lambda{|msg = "world!"| puts "hello #{msg}"}    ->{puts "hello"}  ->(msg="world!"){puts "hello #{msg}"}

以上就是Ruby提供的所有块(block)对象, 都是Proc类的对象。

3. 用不用块(block),是你的自由,但是方法天生就是块的魂归之地。

Ruby中任何一个方法你都可以传递一个块。

   def test;end   test{ puts i}

上面的代码,甚至都不会报错,因为在test方法内部没有去使用这个块(block)。
显然,你已经不能把块(block)当成那个常规的方法参数了,虽然它的行为像参数。

4. 如何使用块(block), 直接决定了它的命运!

A. 在方法内部使用yield关键字去引block的"魂"。

  def test    yield  end  test{puts "hello test!"}    def test(x)    yield(x)  end  test('world!'){|x| puts "hello #{x}"}

yield关键字不仅可以挂载块(block)代码,而且可以给块传递参数。

B. 魂归自身式:使用「&」让一个传递给方法的块(block)魂归自身。

  def test(&block)    block.call("world")  end    test{|msg| puts "hello #{msg}"}

但是在方法内部,也可以使用「&」给块对象(Proc对象)抽魂:

  def test(&block)    inner_test(&block)  end    def inner_test    yield("haha!")  end    test{|msg| puts "hello #{msg}"}

方法真阴险!有木有?

5. 争风吃醋的block兄弟。

{...}和do ... end,虽然是块(block)孪生兄弟,但是也有个谁先谁后的,使用的时候注意,否则它们会让你知道谁才是老大!

  def test(block)    block.call  end    test lambda do      puts "hello"  end

你给test方法传递了一个自由的Proc对象,但是稍有不同,这个Proc对象是用do...end,但是,你执行代码后会发现,这段代码会抛出异常:ArgumentError: tried to create Proc object without a block

  test( lambda do          puts "hello"        end      )

必须要这么修改才可以正常执行。或者使用:

  test lambda{puts "hello"}

这样也可以正常工作。

可以看得出来, do...end 不如 {...}优先级高,{...}亲近离它最近的那个lambda, 而do...end却亲近最远的那个test。
感觉do...end有点混,所以类似于这种把Proc对象传递给方法的时候,一定要注意用括号,或者用{...}

不过由于这个抛出的异常,ArgumentError: tried to create Proc object without a block,我们倒是可以得到一个隐式传递block给方法的写法:

  def test    proc_obj = Proc.new    proc.call  end    test{puts "hello"}

6. 块(block)也有自尊。

  def test    x = 1    yield(x)  end    x = 2  test{ puts x }

块(block)有个超能力,穿透作用域。 上面例子里,块(block)并没有使用test方法里的变量x=1, 而是把块(block)作用域外的变量x=2抓在了手里。

7. 对于块(block)的自尊, 方法向你(Rubyist)求助!

  def test    x = 1    yield(x)  end    x = 2  test{ |x| puts x }

你(Rubyist)往块(block)里插入了个参数,顿时霸气侧漏。方法对你感激不尽,你骄傲的昂起了头 。。。

8. 块(block)还是不服!向你(Rubyist)求助,恢复其自由身!

你(Rubyist)帮块(block)实现了自由身,使用lambda对象化了块

  def test    x = 1    lambda{ puts x}  end    lambda_proc_obj = test  lambda_proc_obj.call

这下块对象(lambda_proc_obj)出气了, lambda_proc_obj想啥时候调用就啥时候调用(lambda_proc_obj.call)。
lambda_proc_obj心想:「哥把你这方法打包了,掌握着你的数据(x=1),再也不看你脸色了。」
噢, 原来如此, 让块(block)完全自由以后变成Proc对象, 它就有闭包的超能力了,好可怕!

9. 两种块对象(Proc对象), 两种命运,可悲可叹!。

A. 被方法所奴役 : 必须要执行的代码段

  proc_obj = Proc.new{ return "from proc return"}  # proc_obj = proc {return  "from proc return"}    def test(block)    msg = block.call    puts "hello! #{msg}!"  end    test(proc_obj)

这段代码会抛出LocalJumpError异常, 用Proc.new和proc{}定义的Proc对象,是不能使用return的。
这就意味着,这个Proc对象,一旦被call,就必须要执行完。

注意这里test方法传递一个本身就是Porc的对象,并没有使用&。

再看看这段代码,看看这俩Proc对象对arity的关心程度(是否检查块对象的参数个数)

def call_with_too_many_args(closure)  begin      puts "closure arity: #{closure.arity}"      closure.call(1,2,3,4,5,6)      puts "Too many args worked"  rescue Exception => e      puts "Too many args threw exception #{e.class}: #{e}"  endend def two_arg_method(x,y)endputs "Proc.new:"; call_with_too_many_args(Proc.new {|x,y|})puts "proc:"    ; call_with_too_many_args(proc {|x,y|})

这段代码可以看出来, Proc.new或proc{}定义的proc对象,完全是方法的奴隶啊!
工作必须执行完不说(无法return),参数个数给传多少都不能发出半点怨言啊!僵尸? 奴隶?

B. 一段匿名的方法体

  lambda_proc_obj = lambda{return "return from lambda proc"}  # lambda_proc_obj = ->{return "return from lambda proc"}  def test(block)    msg = block.call    puts "hello! #{msg}!"  end    test(lambda_proc_obj)

可以看得出来,lambda proc对象是可以正常返回的.

  puts "lambda:"  ; call_with_too_many_args(lambda {|x,y|})

这段代码,就明白了,lambda{}方式创建的Proc对象,才是真正的自由块对象啊!
工作想休息的时候就休息(可以return), 给传的参数多了,也可以发出怨言。
自由的空气,真好。

看来lambda proc和Method对象,有点类似:

  puts "Method:"  ; call_with_too_many_args(method(:two_arg_method))

10. 你(Rubyist)有四种方式对可怜的块对象呼来喝去。

  lm_proc_obj = lambda{puts  "hello world!"}    lm_proc_obj.call  lm_proc_obj.() #无参数必须给一个空的括号  lm_proc_obj[] #无参数必须给一个空的中括号    lm_proc_obj = lambda{|msg| puts  "hello #{msg}!"}    lm_proc_obj.call("world")  lm_proc_obj.("world")   lm_proc_obj["world"]  lm_proc_obj === "world"

看到第四种方式,你应该想到,你可以在case语句里使用proc对象了吧?

  def response_code?(code)    ->(response) { response.code == code }  end  case response  when response_code?(200) then 'OK'  when response_code?(404) then 'Not found'  else 'Unknown code'  end

关于"Ruby的block怎么使用"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

0