Ruby 中的块和收益

发布于 2024-09-06 06:30:26 字数 145 浏览 7 评论 0原文

我试图了解块和产量以及它们在 Ruby 中的工作原理。

如何使用yield?我研究过的许多 Rails 应用程序都以一种奇怪的方式使用 yield

有人可以向我解释或告诉我去哪里理解它们吗?

I am trying to understand blocks and yield and how they work in Ruby.

How is yield used? Many of the Rails applications I've looked at use yield in a weird way.

Can someone explain to me or show me where to go to understand them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

记忆で 2024-09-13 06:30:26

是的,一开始有点令人困惑。

在 Ruby 中,方法可以接收代码块以执行任意代码段。

当方法需要块时,您可以通过调用 yield 函数来调用它。

示例:

Person 为例,它是一个具有 name 属性和 do_with_name 方法的类。当调用该方法时,它将把 name 属性传递给块。

class Person 
    def initialize( name ) 
         @name = name
    end

    def do_with_name   # expects a block
        yield( @name ) # invoke the block and pass the `@name` attribute
    end
end

现在您可以调用此方法并传递任意代码块。

person = Person.new("Oscar")

# Invoking the method passing a block to print the value
person.do_with_name do |value|
    puts "Got: #{value}"
end

将打印:

Got: Oscar

请注意,该块接收一个名为 value 的变量作为参数。当代码调用 yield 时,它会将 @name 的值作为参数传递。

yield( @name )

可以使用不同的块调用相同的方法。

例如反转名称:

reversed_name = ""

# Invoke the method passing a different block
person.do_with_name do |value| 
    reversed_name = value.reverse
end

puts reversed_name

=> "racsO"

其他更有趣的现实生活示例:

过滤数组中的元素:

 days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]  

 # Select those which start with 'T' 
 days.select do | item |
     item.match /^T/
 end

=> ["Tuesday", "Thursday"]

或按名称长度排序:

 days.sort do |x,y|
    x.size <=> y.size
 end

=> ["Monday", "Friday", "Tuesday", "Thursday", "Wednesday"]

如果块是可选的,则可以使用:

yield(value) if block_given?

如果不是可选的,则只需调用它。

您可以使用 irb 在计算机上尝试这些示例(交互式 Ruby Shell

以下是复制/粘贴就绪形式的所有示例:

class Person 
    def initialize( name ) 
         @name = name
    end

    def do_with_name   # expects a block
        yield( @name ) # invoke the block and pass the `@name` attribute
    end
end


person = Person.new("Oscar")

# Invoking the method passing a block to print the value
person.do_with_name do |value|
    puts "Got: #{value}"
end


reversed_name = ""

# Invoke the method passing a different block
person.do_with_name do |value| 
    reversed_name = value.reverse
end

puts reversed_name



# Filter elements in an array:    
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]  

# Select those which start with 'T' 
days.select do | item |
    item.match /^T/
end



# Sort by name length:     
days.sort do |x,y|
   x.size <=> y.size
end

Yes, it is a bit puzzling at first.

In Ruby, methods can receive a code block in order to perform arbitrary segments of code.

When a method expects a block, you can invoke it by calling the yield function.

Example:

Take Person, a class with a name attribute and a do_with_name method. When the method is invoked it will pass the name attribute to the block.

class Person 
    def initialize( name ) 
         @name = name
    end

    def do_with_name   # expects a block
        yield( @name ) # invoke the block and pass the `@name` attribute
    end
end

Now you can invoke this method and pass an arbitrary code block.

person = Person.new("Oscar")

# Invoking the method passing a block to print the value
person.do_with_name do |value|
    puts "Got: #{value}"
end

Would print:

Got: Oscar

Notice the block receives as a parameter a variable called value. When the code invokes yield it passes as argument the value of @name.

yield( @name )

The same method can be invoked with a different block.

For instance to reverse the name:

reversed_name = ""

# Invoke the method passing a different block
person.do_with_name do |value| 
    reversed_name = value.reverse
end

puts reversed_name

=> "racsO"

Other more interesting real life examples:

Filter elements in an array:

 days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]  

 # Select those which start with 'T' 
 days.select do | item |
     item.match /^T/
 end

=> ["Tuesday", "Thursday"]

Or sort by name length:

 days.sort do |x,y|
    x.size <=> y.size
 end

=> ["Monday", "Friday", "Tuesday", "Thursday", "Wednesday"]

If the block is optional you can use:

yield(value) if block_given?

If is not optional, just invoke it.

You can try these examples on your computer with irb (Interactive Ruby Shell)

Here are all the examples in a copy/paste ready form:

class Person 
    def initialize( name ) 
         @name = name
    end

    def do_with_name   # expects a block
        yield( @name ) # invoke the block and pass the `@name` attribute
    end
end


person = Person.new("Oscar")

# Invoking the method passing a block to print the value
person.do_with_name do |value|
    puts "Got: #{value}"
end


reversed_name = ""

# Invoke the method passing a different block
person.do_with_name do |value| 
    reversed_name = value.reverse
end

puts reversed_name



# Filter elements in an array:    
days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]  

# Select those which start with 'T' 
days.select do | item |
    item.match /^T/
end



# Sort by name length:     
days.sort do |x,y|
   x.size <=> y.size
end
靑春怀旧 2024-09-13 06:30:26

在 Ruby 中,方法可以检查它们的调用方式是否除了正常参数之外还提供了块。通常,这是使用 block_given? 方法完成的,但您也可以通过在最终参数名称之前添加前缀 & 符号 (&) 来将该块引用为显式 Proc。

如果使用块调用方法,则如果需要,该方法可以使用一些参数将控制权交给块(调用块)。考虑这个示例方法,它演示了:

def foo(x)
  puts "OK: called as foo(#{x.inspect})"
  yield("A gift from foo!") if block_given?
end

foo(10)
# OK: called as foo(10)
foo(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as foo(123)
# BLOCK: A gift from foo! How nice =)

或者,使用特殊的块参数语法:

def bar(x, &block)
  puts "OK: called as bar(#{x.inspect})"
  block.call("A gift from bar!") if block
end

bar(10)
# OK: called as bar(10)
bar(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as bar(123)
# BLOCK: A gift from bar! How nice =)

In Ruby, methods can check to see if they were called in such a way that a block was provided in addition to the normal arguments. Typically this is done using the block_given? method but you can also refer to the block as an explicit Proc by prefixing an ampersand (&) before the final argument name.

If a method is invoked with a block then the method can yield control to the block (call the block) with some arguments, if needed. Consider this example method that demonstrates:

def foo(x)
  puts "OK: called as foo(#{x.inspect})"
  yield("A gift from foo!") if block_given?
end

foo(10)
# OK: called as foo(10)
foo(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as foo(123)
# BLOCK: A gift from foo! How nice =)

Or, using the special block argument syntax:

def bar(x, &block)
  puts "OK: called as bar(#{x.inspect})"
  block.call("A gift from bar!") if block
end

bar(10)
# OK: called as bar(10)
bar(123) {|y| puts "BLOCK: #{y} How nice =)"}
# OK: called as bar(123)
# BLOCK: A gift from bar! How nice =)
土豪我们做朋友吧 2024-09-13 06:30:26

很可能有人会在这里提供真正详细的答案,但我总是发现 这篇来自 Robert Sosinski 的文章 很好地解释了块、过程和表达式之间的微妙之处。拉姆达。

我应该补充一点,我相信我链接的帖子是特定于 ruby​​ 1.8 的。 ruby 1.9 中发生了一些变化,例如块变量是块的本地变量。在 1.8 中,您会得到类似以下内容的信息:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"

而 1.9 则会显示:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"

我这台机器上没有 1.9,因此上面的内容可能有错误。

It's quite possible that someone will provide a truly detailed answer here, but I've always found this post from Robert Sosinski to be a great explanation of the subtleties between blocks, procs & lambdas.

I should add that I believe the post I'm linking to is specific to ruby 1.8. Some things have changed in ruby 1.9, such as block variables being local to the block. In 1.8, you'd get something like the following:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"

Whereas 1.9 would give you:

>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"

I don't have 1.9 on this machine so the above might have an error in it.

淡忘如思 2024-09-13 06:30:26

我发现这篇文章非常有用。特别是下面的示例:

#!/usr/bin/ruby

def test
  yield 5
  puts "You are in the method test"
  yield 100
end

test {|i| puts "You are in the block #{i}"}

test do |i|
    puts "You are in the block #{i}"
end

应该给出以下输出:

You are in the block 5
You are in the method test
You are in the block 100
You are in the block 5
You are in the method test
You are in the block 100

因此,每次调用 yield 时,ruby 都会运行 do 块中或 do 块中的代码。代码>{}。如果为 yield 提供了参数,则该参数将作为参数提供给 do 块。

对我来说,这是我第一次真正理解 do 块的作用。它基本上是函数访问内部数据结构的一种方式,无论是迭代还是函数配置。

因此,在 Rails 中,您可以编写以下内容:

respond_to do |format|
  format.html { render template: "my/view", layout: 'my_layout' }
end

这将运行 respond_to 函数,该函数生成带有(内部)format 参数的 do 块。然后,您可以在此内部变量上调用 .html 函数,该函数又会生成用于运行 render 命令的代码块。请注意,.html 仅当它是所请求的文件格式时才会产生。 (技术性:这些函数实际上使用 block.call 而不是 yield,正如您从 source 但功能本质上是相同的,请参阅

或者换句话说,它类似于一个函数以匿名函数作为参数,然后在 javascript 中调用它。

I found this article to be very useful. In particular, the following example:

#!/usr/bin/ruby

def test
  yield 5
  puts "You are in the method test"
  yield 100
end

test {|i| puts "You are in the block #{i}"}

test do |i|
    puts "You are in the block #{i}"
end

which should give the following output:

You are in the block 5
You are in the method test
You are in the block 100
You are in the block 5
You are in the method test
You are in the block 100

So essentially each time a call is made to yield ruby will run the code in the do block or inside {}. If a parameter is provided to yield then this will be provided as a parameter to the do block.

For me, this was the first time that I understood really what the do blocks were doing. It is basically a way for the function to give access to internal data structures, be that for iteration or for configuration of the function.

So when in rails you write the following:

respond_to do |format|
  format.html { render template: "my/view", layout: 'my_layout' }
end

This will run the respond_to function which yields the do block with the (internal) format parameter. You then call the .html function on this internal variable which in turn yields the code block to run the render command. Note that .html will only yield if it is the file format requested. (technicality: these functions actually use block.call not yield as you can see from the source but the functionality is essentially the same, see this question for a discussion.) This provides a way for the function to perform some initialisation then take input from the calling code and then carry on processing if required.

Or put another way, it's similar to a function taking an anonymous function as an argument and then calling it in javascript.

我早已燃尽 2024-09-13 06:30:26

我想在已经很好的答案中添加为什么你会这样做。

不知道你来自什么语言,但假设它是静态语言,这种事情看起来很熟悉。这就是你在java中读取文件的方式

public class FileInput {

  public static void main(String[] args) {

    File file = new File("C:\\MyFile.txt");
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    DataInputStream dis = null;

    try {
      fis = new FileInputStream(file);

      // Here BufferedInputStream is added for fast reading.
      bis = new BufferedInputStream(fis);
      dis = new DataInputStream(bis);

      // dis.available() returns 0 if the file does not have more lines.
      while (dis.available() != 0) {

      // this statement reads the line from the file and print it to
        // the console.
        System.out.println(dis.readLine());
      }

      // dispose all the resources after using them.
      fis.close();
      bis.close();
      dis.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

忽略整个流链接的事情,这个想法是

  1. 初始化需要清理的资源
  2. 使用资源
  3. 确保清理它

这与你在ruby中的做法

File.open("readfile.rb", "r") do |infile|
    while (line = infile.gets)
        puts "#{counter}: #{line}"
        counter = counter + 1
    end
end

截然不同。分解这一点,

  1. 告诉 File 类如何初始化资源,
  2. 告诉文件类如何处理它,
  3. 嘲笑那些还在打字的 java 人;-)

在这里,您基本上不用处理第一步和第二步,而是将其委托给另一堂课。正如您所看到的,这极大地减少了您必须编写的代码量,从而使代码更易于阅读,并减少了内存泄漏或文件锁未清除等问题的可能性。

现在,并不是说你不能在 java 中做类似的事情,事实上,人们已经这样做了几十年了。它称为策略模式。不同之处在于,如果没有块,对于像文件示例这样的简单内容,由于需要编写的类和方法的数量,策略就变得矫枉过正。使用块,这是一种简单而优雅的方法,不以这种方式构建代码是没有任何意义的。

这不是使用块的唯一方式,但其他方式(例如 Builder 模式,您可以在 Rails 中的 form_for api 中看到)非常相似,一旦您了解了这一点,就会很明显发生了什么。当您看到块时,通常可以安全地假设该方法调用就是您想要执行的操作,并且该块正在描述您想要如何执行它。

I wanted to sort of add why you would do things that way to the already great answers.

No idea what language you are coming from, but assuming it is a static language, this sort of thing will look familiar. This is how you read a file in java

public class FileInput {

  public static void main(String[] args) {

    File file = new File("C:\\MyFile.txt");
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    DataInputStream dis = null;

    try {
      fis = new FileInputStream(file);

      // Here BufferedInputStream is added for fast reading.
      bis = new BufferedInputStream(fis);
      dis = new DataInputStream(bis);

      // dis.available() returns 0 if the file does not have more lines.
      while (dis.available() != 0) {

      // this statement reads the line from the file and print it to
        // the console.
        System.out.println(dis.readLine());
      }

      // dispose all the resources after using them.
      fis.close();
      bis.close();
      dis.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Ignoring the whole stream chaining thing, The idea is this

  1. Initialize resource that needs to be cleaned up
  2. use resource
  3. make sure to clean it up

This is how you do it in ruby

File.open("readfile.rb", "r") do |infile|
    while (line = infile.gets)
        puts "#{counter}: #{line}"
        counter = counter + 1
    end
end

Wildly different. Breaking this one down

  1. tell the File class how to initialize the resource
  2. tell the file class what to do with it
  3. laugh at the java guys who are still typing ;-)

Here, instead of handling step one and two, you basically delegate that off into another class. As you can see, that dramatically brings down the amount of code you have to write, which makes things easier to read, and reduces the chances of things like memory leaks, or file locks not getting cleared.

Now, its not like you can't do something similar in java, in fact, people have been doing it for decades now. It's called the Strategy pattern. The difference is that without blocks, for something simple like the file example, strategy becomes overkill due to the amount of classes and methods you need to write. With blocks, it is such a simple and elegant way of doing it, that it doesn't make any sense NOT to structure your code that way.

This isn't the only way blocks are used, but the others (like the Builder pattern, which you can see in the form_for api in rails) are similar enough that it should be obvious whats going on once you wrap your head around this. When you see blocks, its usually safe to assume that the method call is what you want to do, and the block is describing how you want to do it.

走过海棠暮 2024-09-13 06:30:26

在 Ruby 中,块基本上是可以传递给任何方法并由任何方法执行的代码块。块始终与方法一起使用,方法通常向块提供数据(作为参数)。

块广泛用于 Ruby gem(包括 Rails)和编写良好的 Ruby 代码中。它们不是对象,因此不能分配给变量。

基本语法

块是由 { } 或 do..end 括起来的一段代码。按照约定,大括号语法应用于单行块,而 do..end 语法应用于多行块。

{ # This is a single line block }

do
  # This is a multi-line block
end 

任何方法都可以接收块作为隐式参数。块由方法内的yield 语句执行。基本语法是:

def meditate
  print "Today we will practice zazen"
  yield # This indicates the method is expecting a block
end 

# We are passing a block as an argument to the meditate method
meditate { print " for 40 minutes." }

Output:
Today we will practice zazen for 40 minutes.

当到达yield语句时,meditate方法将控制权交给块,​​执行块内的代码并将控制权返回给方法,该方法在yield语句之后立即恢复执行。

当一个方法包含yield语句时,它期望在调用时接收一个块。如果未提供块,则一旦到达yield 语句就会抛出异常。我们可以使该块可选并避免引发异常:

def meditate
  puts "Today we will practice zazen."
  yield if block_given? 
end meditate

Output:
Today we will practice zazen. 

不可能将多个块传递给一个方法。每种方法只能接收一个块。

查看更多信息:http://www.zenruby.info /2016/04/introduction-to-blocks-in-ruby.html

In Ruby, a block is basically a chunk of code that can be passed to and executed by any method. Blocks are always used with methods, which usually feed data to them (as arguments).

Blocks are widely used in Ruby gems (including Rails) and in well-written Ruby code. They are not objects, hence cannot be assigned to variables.

Basic Syntax

A block is a piece of code enclosed by { } or do..end. By convention, the curly brace syntax should be used for single-line blocks and the do..end syntax should be used for multi-line blocks.

{ # This is a single line block }

do
  # This is a multi-line block
end 

Any method can receive a block as an implicit argument. A block is executed by the yield statement within a method. The basic syntax is:

def meditate
  print "Today we will practice zazen"
  yield # This indicates the method is expecting a block
end 

# We are passing a block as an argument to the meditate method
meditate { print " for 40 minutes." }

Output:
Today we will practice zazen for 40 minutes.

When the yield statement is reached, the meditate method yields control to the block, the code within the block is executed and control is returned to the method, which resumes execution immediately following the yield statement.

When a method contains a yield statement, it is expecting to receive a block at calling time. If a block is not provided, an exception will be thrown once the yield statement is reached. We can make the block optional and avoid an exception from being raised:

def meditate
  puts "Today we will practice zazen."
  yield if block_given? 
end meditate

Output:
Today we will practice zazen. 

It is not possible to pass multiple blocks to a method. Each method can receive only one block.

See more at: http://www.zenruby.info/2016/04/introduction-to-blocks-in-ruby.html

鸠魁 2024-09-13 06:30:26

我有时会这样使用“yield”:

def add_to_http
   "http://#{yield}"
end

puts add_to_http { "www.example.com" }
puts add_to_http { "www.victim.com"}

I sometimes use "yield" like this:

def add_to_http
   "http://#{yield}"
end

puts add_to_http { "www.example.com" }
puts add_to_http { "www.victim.com"}
腹黑女流氓 2024-09-13 06:30:26

简单来说,Yields 允许您创建的方法接受和调用块。明确来说,yield 关键字是块中“内容”将被执行的位置。

Yields, to put it simply, allow the method you create to take and call blocks. The yield keyword specifically is the spot where the 'stuff' in the block will be performed.

信仰 2024-09-13 06:30:26

关于yield,我想在这里提出两点。首先,虽然这里的很多答案都讨论了将块传递给使用yield的方法的不同方法,但我们也讨论一下控制流。这尤其重要,因为您可以多次生成一个块。我们来看一个例子:

class Fruit
  attr_accessor :kinds

  def initialize 
    @kinds = %w(orange apple pear banana)
  end

  def each 
    puts 'inside each'
    3.times { yield (@kinds.tap {|kinds| puts "selecting from #{kinds}"} ).sample }
  end  
end

f = Fruit.new
f.each do |kind|
  puts 'inside block'
end    

=> inside each
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block

当调用each方法时,它会逐行执行。现在,当我们到达 3.times 块时,该块将被调用 3 次。每次它调用yield。该yield 链接到与调用each 方法的方法关联的块。值得注意的是,每次调用yield 时,它都会将控制权返回给客户端代码中的each 方法的块。一旦该块执行完毕,它就会返回到 3.times 块。并且这种情况发生了 3 次。因此,客户端代码中的该块会在 3 个不同的场合被调用,因为 Yield 被显式调用了 3 次。

我的第二点是关于 enum_for 和 Yield。 enum_for 实例化 Enumerator 类,并且此 Enumerator 对象也响应yield。

class Fruit
  def initialize
    @kinds = %w(orange apple)
  end

  def kinds
    yield @kinds.shift
    yield @kinds.shift
  end
end

f = Fruit.new
enum = f.to_enum(:kinds)
enum.next
 => "orange" 
enum.next
 => "apple" 

因此请注意,每次我们使用外部迭代器调用种类时,它只会调用一次yield。下次我们调用它时,它将调用下一个yield,依此类推。

关于 enum_for 有一个有趣的花絮。在线文档声明如下:

enum_for(method = :each, *args) → enum
Creates a new Enumerator which will enumerate by calling method on obj, passing args if any.

str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }    
# => 120
# => 121
# => 122

如果您没有指定符号作为 enum_for 的参数,ruby 会将枚举器挂接到接收者的each 方法。有些类没有each 方法,例如String 类。

str = "I like fruit"
enum = str.to_enum
enum.next
=> NoMethodError: undefined method `each' for "I like fruit":String

因此,对于使用 enum_for 调用某些对象的情况,您必须明确您的枚举方法是什么。

There are two points I want to make about yield here. First, while a lot of answers here talk about different ways to pass a block to a method which uses yield, let's also talk about the control flow. This is especially relevant since you can yield MULTIPLE times to a block. Let's take a look at an example:

class Fruit
  attr_accessor :kinds

  def initialize 
    @kinds = %w(orange apple pear banana)
  end

  def each 
    puts 'inside each'
    3.times { yield (@kinds.tap {|kinds| puts "selecting from #{kinds}"} ).sample }
  end  
end

f = Fruit.new
f.each do |kind|
  puts 'inside block'
end    

=> inside each
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block
=> selecting from ["orange", "apple", "pear", "banana"]
=> inside block

When the each method is invoked, it executes line by line. Now when we get to the 3.times block, this block will be invoked 3 times. Each time it invokes yield. That yield is linked to the block associated with the method that called the each method. It is important to notice that each time yield is invoked, it returns control back to the block of the each method in client code. Once the block is finished executing, it returns back to the 3.times block. And this happens 3 times. So that block in client code is invoked on 3 separate occasions since yield is explicitly called 3 separate times.

My second point is about enum_for and yield. enum_for instantiates the Enumerator class and this Enumerator object also responds to yield.

class Fruit
  def initialize
    @kinds = %w(orange apple)
  end

  def kinds
    yield @kinds.shift
    yield @kinds.shift
  end
end

f = Fruit.new
enum = f.to_enum(:kinds)
enum.next
 => "orange" 
enum.next
 => "apple" 

So notice every time we invoke kinds with the external iterator, it will invoke yield only once. The next time we call it, it will invoke the next yield and so on.

There's an interesting tidbit with regards to enum_for. The documentation online states the following:

enum_for(method = :each, *args) → enum
Creates a new Enumerator which will enumerate by calling method on obj, passing args if any.

str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }    
# => 120
# => 121
# => 122

If you do not specify a symbol as an argument to enum_for, ruby will hook the enumerator to the receiver's each method. Some classes do not have an each method, like the String class.

str = "I like fruit"
enum = str.to_enum
enum.next
=> NoMethodError: undefined method `each' for "I like fruit":String

Thus, in the case of some objects invoked with enum_for, you must be explicit as to what your enumerating method will be.

最佳男配角 2024-09-13 06:30:26

Yield 可以用作无名块以在方法中返回值。考虑以下代码:

Def Up(anarg)
  yield(anarg)
end

您可以创建一个方法“Up”,并为其分配一个参数。您现在可以将此参数分配给yield,它将调用并执行关联的块。您可以在参数列表之后分配块。

Up("Here is a string"){|x| x.reverse!; puts(x)}

当Up方法调用yield时,带有一个参数,它被传递给块变量来处理请求。

Yield can be used as nameless block to return a value in the method. Consider the following code:

Def Up(anarg)
  yield(anarg)
end

You can create a method "Up" which is assigned one argument. You can now assign this argument to yield which will call and execute an associated block. You can assign the block after the parameter list.

Up("Here is a string"){|x| x.reverse!; puts(x)}

When the Up method calls yield, with an argument, it is passed to the block variable to process the request.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文