温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Ruby的block怎么使用

发布时间:2022-01-14 14:46:17 来源:亿速云 阅读:151 作者:iii 栏目:大数据

这篇文章主要介绍“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怎么使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI