Ruby中的块和产量
我试图理解块和Ruby中的块和产量,ruby,block,Ruby,Block,我试图理解块和产生以及它们在Ruby中的工作方式 如何使用yield?我看过的许多Rails应用程序都以一种奇怪的方式使用产生 有人能给我解释一下或者告诉我去哪里理解它们吗?在Ruby中,方法可以检查它们的调用方式是否在正常参数之外还提供了一个块。通常,这是使用block\u given?方法完成的,但您也可以通过在最终参数名称前加上一个符号(&)将该块作为显式过程引用 如果使用块调用一个方法,那么如果需要,该方法可以使用一些参数将控制权交给块(调用块)。考虑这个示例方法,演示: def foo
产生以及它们在Ruby中的工作方式
如何使用yield
?我看过的许多Rails应用程序都以一种奇怪的方式使用产生
有人能给我解释一下或者告诉我去哪里理解它们吗?在Ruby中,方法可以检查它们的调用方式是否在正常参数之外还提供了一个块。通常,这是使用block\u given?
方法完成的,但您也可以通过在最终参数名称前加上一个符号(&
)将该块作为显式过程引用
如果使用块调用一个方法,那么如果需要,该方法可以使用一些参数将控制权交给块(调用块)。考虑这个示例方法,演示:
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 =)
很可能有人会在这里提供一个真正详细的答案,但我总是从Robert Sosinski那里发现,这是对块、过程和lambdas之间微妙关系的一个很好的解释
我应该补充一点,我相信我链接到的帖子是ruby 1.8特有的。Ruby1.9中的一些东西已经改变了,比如块变量是块的局部变量。在1.8中,您将得到如下内容:
>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Goodbye"
respond_to do |format|
format.html { render template: "my/view", layout: 'my_layout' }
end
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
鉴于1.9将为您提供:
>> a = "Hello"
=> "Hello"
>> 1.times { |a| a = "Goodbye" }
=> 1
>> a
=> "Hello"
我在这台机器上没有1.9版本,所以上面可能有一个错误。我想在已经很好的答案中添加为什么你会这样做
不知道您来自哪种语言,但假设它是一种静态语言,这类事情看起来会很熟悉。这就是用java读取文件的方式
公共类文件输入{
公共静态void main(字符串[]args){
File File=新文件(“C:\\MyFile.txt”);
FileInputStream fis=null;
BufferedInputStream bis=null;
DataInputStream dis=null;
试一试{
fis=新文件输入流(文件);
//此处添加了BufferedInputStream以实现快速读取。
bis=新的缓冲数据流(fis);
dis=新数据输入流(bis);
//如果文件没有更多行,则dis.available()返回0。
while(dis.available()!=0){
//此语句从文件中读取该行并将其打印到
//控制台。
System.out.println(dis.readLine());
}
//使用完所有资源后,请进行处置。
fis.close();
二、关闭();
dis.close();
}catch(filenotfounde异常){
e、 printStackTrace();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
忽略整个流链接的事情,想法是这样的
初始化需要清理的资源
使用资源
一定要把它清理干净
在ruby中就是这样做的
File.open("readfile.rb", "r") do |infile|
while (line = infile.gets)
puts "#{counter}: #{line}"
counter = counter + 1
end
end
完全不同。把这个拆了
告诉File类如何初始化资源
告诉file类如何处理它
嘲笑那些还在打字的java家伙;-)李>
在这里,您不需要处理第一步和第二步,而是将其委托给另一个类。正如您所看到的,这大大减少了您必须编写的代码量,从而使内容更易于阅读,并减少了内存泄漏或文件锁未被清除的可能性
现在,并不是说你不能在java中做类似的事情,事实上,人们已经做了几十年了。这就是所谓的模式。不同之处在于,如果没有块,对于像文件示例这样简单的东西,由于需要编写的类和方法的数量太多,策略变得过于复杂。对于块,这是一种非常简单和优雅的方式,因此不以这种方式构造代码是没有任何意义的
这并不是使用块的唯一方式,但其他方式(如构建器模式,您可以在rails中api的形式_中看到)非常相似,一旦您了解了这一点,就会清楚地知道发生了什么。当您看到块时,通常可以安全地假设方法调用是您想要做的,并且块描述了您想要如何做。是的,一开始有点令人费解
在Ruby中,方法可以接收代码块以执行任意代码段
当一个方法需要一个块时,它通过调用yield
函数来调用它
例如,这非常方便,可以迭代列表或提供自定义算法
以以下为例:
#!/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
我将定义一个用名称初始化的Person
类,并提供一个do_with_name
方法,调用该方法时,只需将name
属性传递给接收到的块
class Person
def initialize( name )
@name = name
end
def do_with_name
yield( @name )
end
end
这将允许我们调用该方法并传递任意代码块
例如,要打印名称,我们将执行以下操作:
person = Person.new("Oscar")
#invoking the method passing a block
person.do_with_name do |name|
puts "Hey, his name is #{name}"
end
将打印:
Hey, his name is Oscar
请注意,该块作为参数接收一个名为name
(注意,您可以随意调用该变量,但调用name
)的变量。当代码调用yield
时,它会用@name
的值填充此参数
yield( @name )
我们可以提供另一个块来执行不同的操作。例如,反转名称:
#variable to hold the name reversed
reversed_name = ""
#invoke the method passing a different block
person.do_with_name do |name|
reversed_name = name.reverse
end
puts reversed_name
=> "racsO"
我们使用了完全相同的方法(do_with_name
)-它只是一个不同的块
这个例子很简单。更有趣的用法是过滤数组中的所有元素:
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"]
如果不是可选的,就调用它
编辑
@hmak为这些示例创建了一个repl.it:简单地说,就是允许您创建的方法获取和调用块。yield关键字是执行块中“stuff”的位置。我发现它非常有用。特别是以下示例:
#!/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
哪个应该
def add_to_http
"http://#{yield}"
end
puts add_to_http { "www.example.com" }
puts add_to_http { "www.victim.com"}
{ # This is a single line block }
do
# This is a multi-line block
end
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.
def meditate
puts "Today we will practice zazen."
yield if block_given?
end meditate
Output:
Today we will practice zazen.
Def Up(anarg)
yield(anarg)
end
Up("Here is a string"){|x| x.reverse!; puts(x)}
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
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"
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
str = "I like fruit"
enum = str.to_enum
enum.next
=> NoMethodError: undefined method `each' for "I like fruit":String