You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中attr_accessor在Proc内无法正常访问的技术问题

Ruby中类变量在闭包proc里无法访问的解决方案

你遇到的问题是:通过attr_accessor定义的类属性size,在content_length_proc中赋值后,progress_proc里无法访问到这个值。先看一下问题代码里的关键坑点:

require 'open-uri'
MEGABYTE = 1024.0 * 1024.0

def bytes_to_megabytes(bytes)
  bytes / MEGABYTE
end

class Downloader
  class << self
    attr_accessor :size

    def get(resource)
      open(resource,
        content_length_proc: proc do |t|
          size = bytes_to_megabytes(t).round
          puts "Total size is: #{size}"
        end,
        progress_proc: proc do |step|
          # size 无法在此处打印!
          puts "Downloading #{bytes_to_megabytes(step).round} out of #{size}"
        end
      )
    end
  end
end

问题根源

  1. setter方法调用错误:在content_length_proc里写size = ...时,Ruby会把它当成局部变量赋值,而不是调用attr_accessor生成的size=类方法。你根本没把值存到类的size属性里。
  2. 闭包作用域问题:就算你正确赋值了,progress_proc的上下文里self并不是Downloader类,直接写size会去当前proc的局部变量里找,自然找不到类属性的值。

修复后的代码

只需要两处小修改,就能解决问题:

require 'open-uri'
MEGABYTE = 1024.0 * 1024.0

def bytes_to_megabytes(bytes)
  bytes / MEGABYTE
end

class Downloader
  class << self
    attr_accessor :size

    def get(resource)
      open(resource,
        content_length_proc: proc do |t|
          # 显式调用self.size=来触发类的setter方法
          self.size = bytes_to_megabytes(t).round
          puts "Total size is: #{self.size}"
        end,
        progress_proc: proc do |step|
          # 通过类名访问类属性,确保拿到正确的值
          puts "Downloading #{bytes_to_megabytes(step).round} out of #{Downloader.size}"
        end
      )
    end
  end
end

修复说明

  • 第一处修改:把size = ...改成self.size = ...,这样Ruby才会调用attr_accessor生成的类setter方法,把值真正存在Downloader类的size属性里。
  • 第二处修改:把progress_proc里的size改成Downloader.size,明确指定访问类的属性,避免闭包作用域的干扰。

这样修改后,progress_proc就能正常获取到总文件大小,正确输出下载进度了。

内容的提问来源于stack exchange,提问作者stratis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:48:49