簡體   English   中英

如何在Ruby中編組lambda(Proc)?

[英]How do I marshal a lambda (Proc) in Ruby?

Joe Van Dyk 詢問了Ruby郵件列表

嗨,

在Ruby中,我猜你不能編組一個lambda / proc對象,對嗎? 在lisp或其他語言中這可能嗎?

我想做什么:

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

所以,我正在向BackgroundJob發送一個lambda對象,該對象包含要執行的操作的上下文/代碼。 但是,猜測這是不可能的。 我最終編組了一個普通的ruby對象,其中包含程序運行后要執行的操作的說明。

你不能編組Lambda或Proc。 這是因為它們都被認為是閉包,這意味着它們靠近定義它們的內存並且可以引用它。 (為了編組它們,你必須將它們在創建時可以訪問的所有內存編組。)

正如Gaius指出的那樣,你可以使用ruby2ruby來獲取程序的字符串。 也就是說,您可以封送代表ruby代碼的字符串,然后再重新評估它。

你也可以輸入你的代碼作為字符串:

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

然后用eval執行它

eval code

這將返回紅寶石lamda。

使用%{}格式轉義字符串,但僅在不匹配的大括號上關閉。 即你可以像這個%{ [] {} }那樣嵌套大括號,它仍然是封閉的。

大多數文本語法熒光筆沒有意識到這是一個字符串,所以仍然顯示常規代碼突出顯示。

如果您對使用Ruby2Ruby獲取Ruby代碼的字符串版本感興趣,您可能會喜歡這個主題

試試ruby2ruby

我發現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

如果將proc定義到文件中,U可以獲取proc的文件位置然后序列化它,然后在反序列化后使用該位置再次返回proc

proc_location_array = proc.source_location

反序列化后:

file_name = 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}”)

曾幾何時,這可能是使用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上運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM