21

Joe Van Dyk询问了 Ruby 邮件列表

你好,

在 Ruby 中,我猜你不能编组一个 lambda/proc 对象,对吧?这可能在 lisp 或其他语言中吗?

我想做的是:

l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)

所以,我正在向 BackgroundJob 发送一个 lambda 对象,其中包含要做什么的上下文/代码。但是,估计那是不可能的。我最终编组了一个普通的 ruby​​ 对象,其中包含程序运行后要做什么的说明。

4

7 回答 7

21

您不能编组 Lambda 或 Proc。这是因为它们都被认为是闭包,这意味着它们在定义它们的内存周围关闭并且可以引用它。(为了编组它们,您必须编组它们在创建时可以访问的所有内存。)

正如 Gaius 指出的那样,您可以使用ruby​​2ruby来获取程序的字符串。也就是说,您可以对表示 ruby​​ 代码的字符串进行编组,然后再重新评估它。

于 2008-09-01T23:10:45.360 回答
12

您也可以将代码作为字符串输入:

code = %{
    lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}

然后用 eval 执行它

eval code

这将返回一个 ruby​​ lamda。

使用%{}格式转义字符串,但仅在不匹配的大括号上关闭。即你可以像这样嵌套大括号%{ [] {} },它仍然是封闭的。

大多数文本语法荧光笔都没有意识到这是一个字符串,所以仍然显示常规代码高亮。

于 2010-09-14T00:14:19.777 回答
4

如果您对使用 Ruby2Ruby 获取字符串版本的 Ruby 代码感兴趣,您可能会喜欢这个线程

于 2010-03-04T03:13:24.487 回答
3

试试ruby​​2ruby

于 2008-08-23T04:24:49.023 回答
1

我发现 proc_to_ast 做得最好:https ://github.com/joker1007/proc_to_ast 。

在 ruby​​ 2+ 中肯定可以工作,并且我为 ruby​​ 1.9.3+ 兼容性创建了一个 PR(https://github.com/joker1007/proc_to_ast/pull/3

于 2015-11-10T00:07:27.053 回答
1

曾几何时,这可以使用 ruby​​-internal gem ( https://github.com/cout/ruby-internal ),例如:

p = proc { 1 + 1 }    #=> #<Proc>
s = Marshal.dump(p)   #=> #<String>
u = Marshal.load(s)   #=> #<UnboundProc>
p2 = u.bind(binding)  #=> #<Proc>
p2.call()             #=> 2

有一些警告,但已经很多年了,我不记得细节了。例如,如果一个变量在它被转储的绑定中是一个 dynvar 并且在它被重新绑定的绑定中是一个本地变量,我不确定会发生什么。序列化 AST(在 MRI 上)或字节码(在 YARV 上)并非易事。

上面的代码适用于 YARV(最高 1.9.3)和 MRI(最高 1.8.7)。没有任何理由不能让它在 Ruby 2.x 上运行,只需付出一点努力。

于 2018-09-16T10:11:32.987 回答
0

如果proc被定义到一个文件中,U可以获取proc的文件位置然后序列化它,然后在反序列化后使用该位置再次回到proc

proc_location_array = proc.source_location

反序列化后:

文件名 = proc_location_array[0]

line_number = proc_location_array[1]

proc_line_code = IO.readlines(file_name)[line_number - 1]

proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]

proc = eval("lambda #{proc_hash_string}")

于 2017-04-11T17:20:59.633 回答