【发布时间】:2010-10-20 07:58:11
【问题描述】:
我最近发现了 Ruby 的块和产生功能,我想知道:这在计算机科学理论方面适合什么?它是一种函数式编程技术,还是更具体的技术?
【问题讨论】:
标签: ruby functional-programming yield
我最近发现了 Ruby 的块和产生功能,我想知道:这在计算机科学理论方面适合什么?它是一种函数式编程技术,还是更具体的技术?
【问题讨论】:
标签: ruby functional-programming yield
Ruby 的 yield 不像 C# 和 Python 中的迭代器。 yield 本身实际上是一个非常简单的概念,一旦您了解了块在 Ruby 中的工作原理。
是的,块是一种函数式编程特性,尽管 Ruby 并不是一种适当的函数式语言。事实上,Ruby 使用 lambda 方法创建块对象,这是从 Lisp 用于创建匿名函数的语法中借用的——这就是块的含义。从计算机科学的角度来看,Ruby 的块(和 Lisp 的 lambda 函数)是closures。在 Ruby 中,方法通常只占用一个块。 (你可以通过更多,但是很尴尬。)
Ruby 中的yield 关键字只是一种调用已赋予方法的块的方式。这两个例子是等价的:
def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end
def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end
在第一种情况下,我们只是假设有一个块并说要调用它。另一方面,Ruby 将块包装在一个对象中并将其作为参数传递。第一个更高效和可读,但它们实际上是相同的。你可以这样称呼任何一个:
with_log do
a = 5
other_num = gets.to_i
@my_var = a + other_num
end
它会打印最终分配给@my_var 的值。 (好吧,这是一个完全愚蠢的功能,但我想你明白了。)
块在 Ruby 中用于很多事情。几乎每一个你会在像 Java 这样的语言中使用循环的地方,它在 Ruby 中都被替换为带块的方法。例如,
[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
正如 Andrew 所说,它也常用于打开文件和许多其他地方。基本上只要你有一个可以使用一些自定义逻辑的标准函数(比如排序数组或处理文件),你就会使用一个块。还有其他用处,不过这个答案已经这么长了,恐怕会导致体质较弱的读者心脏病发作。希望这能消除对该主题的困惑。
【讨论】:
yield 和 blocks 不仅仅是循环。
Enumerating enumerable 系列有一系列可以用枚举做的事情,例如询问某个陈述是否对组中的任何成员为真,或者对所有成员是否为真,或者搜索任何或所有成员满足一定条件。
块对于变量范围也很有用。它不仅方便,还可以帮助进行良好的设计。比如代码
File.open("filename", "w") do |f|
f.puts "text"
end
确保文件流在您完成后关闭,即使发生异常,并且一旦您完成该变量就超出范围。
一个随便的 google 没有想出一篇关于 ruby 块和产量的好博文。我不知道为什么。
对评论的回应:
我怀疑它被关闭是因为块结束,而不是因为变量超出范围。
我的理解是,当指向对象的最后一个变量超出范围时,除了该对象符合垃圾回收条件外,没有什么特别的事情发生。不过,我不知道如何确认。
我可以证明文件对象在被垃圾收集之前就被关闭了,这通常不会立即发生。在下面的示例中,您可以看到在第二个 puts 语句中关闭了一个文件对象,但它还没有被垃圾回收。
g = nil
File.open("/dev/null") do |f|
puts f.inspect # #<File:/dev/null>
puts f.object_id # Some number like 70233884832420
g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
# indicating that g points to the exact same object that f pointed to
【讨论】:
f 超出范围时,Ruby 会自动关闭它?
File#open 方法在使用块调用时,将在块完成后关闭创建的文件句柄。
我认为yield 语句起源于CLU 语言。我一直想知道《创》中的角色是否也以 CLU 命名....
【讨论】:
【讨论】: