美文网首页
yield in ruby

yield in ruby

作者: EvanCui | 来源:发表于2019-04-13 17:09 被阅读0次

ruby中的关键词yield通常在一个方法中调用,对代码块进行控制,如果没有提供对应的代码块,调用该方法将导致异常。

块(block)是ruby的语法中一部分。
在ruby中当一个block被解析器识别到,该block将被关联到调用它的方法上,并替代方法中的yield关键词。

# mymethod方法中调用yield,所以调用mymethod必须传入一个block参数
def mymethod
  puts "this is mymethod before"
  yield
  puts "this is mymethod after"
end

mymethod
#=> this is mymethod before
#=> LocalJumpError: no block given (yield)

mymethod { puts "this is mymethod"}
#=> this is mymethod before
#=> this is mymethod
#=> this is mymethod after

那如何将mymethod中的block变为可选参数呢?
答案是使用block_given?

def mymethod
  puts "this is mymethod before"
  yield if block_given?
  puts "this is mymethod after"
end

mymethod
#=> this is mymethod before
#=> this is mymethod after

mymethod { puts "this is mymethod"}
#=> this is mymethod before
#=> this is mymethod
#=> this is mymethod after

给yield传参数

def another_method
  a = "1"
  b = "5"
  yield(a, b)
end

another_method {|x, y| puts "First arg is #{x}, Second arg is #{y}"}
#=> First arg is 1, Second arg is 5

给yield传self,即当前对象作为参数

module MyModule
  def self.name
    @name ||= "Tomi"
  end
  
  def self.name=(val)
    @name = val
  end
 
  def self.mymethod
    yield(self)  # self表示MyModule
  end
end

MyModule.mymethod do |config|
  config.name = "Eric"
end

MyModule.name
#=> "Eric"

保存yield返回值

def another_method
  a = 1
  b = 5
  result = yield(a, b)
  puts "The result is #{result}"
end

another_method {|x, y| x + y }
#=> The result is 6

重写map方法

# ruby中Array#map使用方法为: [1,2,3].map{|x| x * 2}  #=> [2,4,6]

class Array
  def mymap
    return self.dup unless block_given?
    arr = []
    self.each do |a|  #self is the receiver array
      arr << yield(a)
    end
    arr
  end
end

为什么ruby中有时传入block,但是有时传入&block?
block是一个local variable,但是&block传入的是一个该block的引用(reference)
那&block的作用是什么呢?

  1. 如果该对象是一个block,它将被转化为一个Proc
  2. 如果该对象是一个Proc,它将被转化为一个block
  3. 如果该对象是其它类型值,他将调用to_proc,然后转化为一个block.

示例:

def my_method(&my_block)
  my_block
end

# 第一种情况
传入的my_block为一个block,通过&符将其转化为一个Proc对象
my_method { "x" }   #=> #<Proc:0x00007

#第二种情况
传入一个Proc对象
my_proc = Proc.new { "x" }
my_method(my_proc)  #ArgumentError: wrong number of arguments
my_method(&my_proc)  #=> #<Proc:0x00007

#第三种情况
传入一个既不是Proc也不是block的参数,而是一个符号 :even?
my_method(&:even?)  #=> #<Proc:0x00007
等价于my_method(&:even?.to_proc)

那.map(&:something)怎么工作的呢?

大家熟悉的是该写法等价于.map{|x| x.something}。

简单的说它是.map(&:something.to_proc)的缩写,比如当foo是一个带有to_proc的对象,那你可以使用&foo将其传入一个方法,这样将调用foo.to_proc并且将此作为该方法的block使用

使用默认值来初始化对象:

使用yield(self)来声明对象赋值,在initialize的上下文中,self指向被initialized的对象。

class Car
  attr_accessor :color, :doors
  def initialize
     yield(self)
  end
end

car = Car.new do |c|
  c.color = "red"
  c.doors = 4
end

puts "My car's color is #{car.color}, it has #{car.doors} doors"

总结:
你可以认为block就是一段代码,yield帮助你将这些代码注入一个方法中,这意味着你可以让一个方法按照不同的方式运行,这样你可以重用一个方法做不同的事情。

ref: https://mixandgo.com/learn/mastering-ruby-blocks-in-less-than-5-minutes

相关文章

  • yield in ruby

    ruby中的关键词yield通常在一个方法中调用,对代码块进行控制,如果没有提供对应的代码块,调用该方法将导致异常...

  • yield_self 到 then

    yield_self的作用 ruby 在 2.5.0 引入 了的方法 Kernel#yield_self [Fea...

  • Ruby 块从入门到精通

    “块”是 Ruby 中最有用的特性之一,但是也常常被忽略。开始学习 Ruby 块时,经常被 yield 弄的难以理...

  • Python生成器进阶

    一、yield 简介 二、yield from 功能总结: 三、yield from 的用法:

  • python yield和yield from用法总结

    python yield和yield from用法总结 yield 作用: 注: generator的next()...

  • JAVA多线程08-基础篇-线程让步yield()

    本节摘要:yield()功能介绍,yield()用法示例 一、功能介绍 让当前线程(调用yield()方法的线程)...

  • Python yield

    参考:Python yield 使用浅析 - IBM 递归中使用yield 有时候yield就可以解决递归的问题,...

  • pytest-fixture中的yield及autouse

    记录一下fixture中关于yield以及autouse参数的两个小细节。 yield yield在fixture...

  • CFA level I 数量方法错点

    bank discount yield 360天 effective annual yield 365天 Any ...

  • Python yield关键字

    Python中yield关键字解释 这篇文章关于python的yield关键字。并且文章中会解释什么是yield,...

网友评论

      本文标题:yield in ruby

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