Ruby中的惰性求值

0pizxfdo  于 2023-10-18  发布在  Ruby
关注(0)|答案(3)|浏览(99)

我有一个Ruby的情况,可能需要创建一个对象,但不确定。由于创建对象的成本可能很高,我并不急于创建它。我认为这是一个明显的延迟加载案例。我如何定义一个对象,它不是只有当有人向它发送消息时才创建的?对象将在块中创建。在Ruby中有没有一种简单的惰性加载/初始化的方法?这些东西是否得到了一些gems的支持,这些gems为对象的惰性初始化的各种情况提供了不同的解决方案?谢谢你的建议!

tyu7yeag

tyu7yeag1#

有两种方法。
第一个是让caller处理惰性对象创建。这是最简单的解决方案,也是Ruby代码中非常常见的模式。

class ExpensiveObject
  def initialize
    # Expensive stuff here.
  end
end

class Caller
  def some_method
    my_object.do_something
  end

  def my_object
    # Expensive object is created when my_object is called. Subsequent calls
    # will return the same object.
    @my_object ||= ExpensiveObject.new
  end
end

第二个选择是让对象惰性地初始化自己。我们在实际对象周围创建一个委托对象来实现这一点。这种方法有点棘手,不推荐使用,除非您有无法修改的现有调用代码。

class ExpensiveObject        # Delegate
  class RealExpensiveObject  # Actual object
    def initialize
      # Expensive stuff here.
    end

    # More methods...
  end

  def initialize(*args)
    @init_args = args
  end

  def method_missing(method, *args)
    # Delegate to expensive object. __object method will create the expensive
    # object if necessary.
    __object__.send(method, *args)
  end

  def __object__
    @object ||= RealExpensiveObject.new(*@init_args)
  end
end

# This will only create the wrapper object (cheap).
obj = ExpensiveObject.new

# Only when the first message is sent will the internal object be initialised.
obj.do_something

您也可以使用stdlib delegate在之上构建它。

7dl7o3gd

7dl7o3gd2#

如果你想延迟地计算代码片段,请使用代理:

class LazyProxy

  # blank slate... (use BasicObject in Ruby 1.9)
  instance_methods.each do |method| 
    undef_method(method) unless method =~ /^__/
  end

  def initialize(&lazy_proxy_block)
    @lazy_proxy_block = lazy_proxy_block
  end

  def method_missing(method, *args, &block)
    @lazy_proxy_obj ||= @lazy_proxy_block.call # evaluate the real receiver
    @lazy_proxy_obj.send(method, *args, &block) # delegate unknown methods to the real receiver
  end
end

你可以这样使用它:

expensive_object = LazyProxy.new { ExpensiveObject.new }
expensive_object.do_something

你可以用这段代码来做任何复杂的初始化昂贵的东西:

expensive_object = LazyProxy.new do
  expensive_helper = ExpensiveHelper.new
  do_really_expensive_stuff_with(expensive_helper)
  ExpensiveObject.new(:using => expensive_helper)
end
expensive_object.do_something

它是如何工作的?示例化一个LazyProxy对象,该对象包含有关如何在Proc中构建一些昂贵对象的指令。如果您随后调用代理对象上的某个方法,它首先示例化昂贵对象,然后将方法调用委托给它。

yyyllmsg

yyyllmsg3#

在Ruby 3.x中,我使用gem concurrent-ruby
一个可能的惰性初始化用例如下所示:

require 'concurrent'

# put expensive code inside a "future":
very_lazy = Concurrent::Promises.future { some_expensive_code_block }
# the "future" starts performing work in background

# use
puts very_lazy.value   # blocks, until the "future" is ready
puts very_lazy.value   # repeated calls just re-use existing value
  • 如果我说错了请有人纠正我 *

相关问题