【问题标题】:What is the purpose of the 'proc' parameter in Marshal::load?Marshal::load 中“proc”参数的目的是什么?
【发布时间】:2020-12-08 18:00:18
【问题描述】:

我已经寻找解释其目的的资源。我也找不到任何现实世界的实现。

以下是 Ruby 的documentation 的摘录:

load( source [, proc] ) → obj 返回转换结果 将源中的数据序列化为 Ruby 对象(可能与关联的 从属对象)。 source 可以是 IO 的实例或 响应 to_str 的对象。如果指定了 proc,每个对象将 被传递给 proc,因为对象正在被反序列化。

我会很感激它的使用示例,或者至少将我引导到一些资源。

【问题讨论】:

    标签: ruby deserialization unmarshalling proc


    【解决方案1】:

    您可以通过执行以下操作来查看 proc 是如何被调用的:

    irb(main):030:0> Marshal.load(Marshal.dump(a:1), lambda { |x| p [self,x]; x })
    [main, :a]
    [main, 1]
    [main, {:a=>1}]
    => {:a=>1}
    

    当与编组字符串一起使用时,由于某种原因,proc 会被调用两次。

    irb(main):031:0> Marshal.load(Marshal.dump('a'), lambda { |x| p [self,x]; x })
    [main, "a"]
    [main, true]
    => "a"
    

    【讨论】:

      【解决方案2】:

      反序列化对象的转换

      一般用例是您想要对要反序列化的对象执行一些操作或转换。例如,使用一些 Ruby 2.7.1 快捷方式:

      Marshal.load Marshal.dump("abc"), ->{ _1.to_s.upcase }
      #=> "ABC"
      

      这在反序列化单个对象时不会增加太多价值,但如果您正在处理批量转储的对象,则可能非常有用。我想不出一个实用的用例,你不能在反序列化 之后进行转换,但是 Ruby 有很多有用的工具可以在没有中间步骤的情况下处理事情。这似乎是其中之一。

      可能的错误:Procs 似乎运行两次但返回一次

      在上面的示例中,我将第一个位置参数强制转换为字符串,否则我会在通过 lambda 进行的两次传递中的一次获得 NoMethodError。您可以按如下方式解开正在发生的事情(但也许不是为什么):

      prc = proc { |obj| pp obj }
      Marshal.load Marshal.dump("abc"), prc
      
      "abc"
      true
      #=> "abc"
      

      无论出于何种原因,Proc 或 lambda 的主体都被调用了两次,但只有 返回第一次。当第二次调用在 TrueClass 上调用时引发 NoMethodError 异常时,就会出现问题,因此该调用永远不会返回值。

      另一种处理方式是显式处理异常,例如:

      prc = proc { |obj| obj.upcase rescue NoMethodError }
      

      或避免在true 上调用方法:

      prc = proc { |obj| obj.upcase unless obj == true }
      

      虽然我可以解释 发生了什么 以及如何解决它,但我无法告诉你 为什么 使用类 proc 对象调用会以这种方式运行.这是 Ruby 核心团队的问题,或者是 Ruby bug tracker 的素材。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-22
        • 2019-12-02
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        相关资源
        最近更新 更多