【问题标题】:ruby variable scoping across classes跨类的 ruby​​ 变量作用域
【发布时间】:2012-03-20 14:50:30
【问题描述】:

这里是鲁努比。我有一个类Login 使用net/IMAP 库登录到gmail。发生的事情是我创建了该类的一个新实例,例如:

a = Login.new("username", "gmail.com", "passw")

然后,我正在研究其他可以对邮箱做一些“事情”的课程。问题是我在 Login 中定义的 @imap 变量似乎已经消失(由于我假设的范围)。

这就是@imap 在 Login 类中的声明方式: @imap = Net::IMAP.new('imap.gmail.com',993,true,nil,false)

所以:

  @today = Date.today
  @received_today = imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s

...返回错误。这是我在玩这个时遇到的两个错误。第一个是我使用imap的时候,第二个是我尝试@imap的时候:

NameError: undefined local variable or method `imap' for #<Object:0x10718d2a8>
NoMethodError: undefined method `search' for nil:NilClass

处理此类情况的最佳做法是什么?是在创建 Net::IMAP 的新实例的同一类中定义我的方法的唯一解决方案吗?将@imap 声明为全局变量$imap 是一种不好的做法吗?如此困惑,我敢打赌答案也非常简单明了,但我只是没有看到。谢谢!

【问题讨论】:

    标签: ruby class imap scoping


    【解决方案1】:

    在 User 类中定义 imap 变量的更短的方法,这与 mu 发布的几乎相同:

    class User
       def imap
          @imap ||= Net::IMAP.new...
       end
    end
    

    【讨论】:

    • 谢谢。我喜欢 Ruby 有多种解决问题的方法。很高兴学习新事物,例如 ||=
    【解决方案2】:

    这个:

    @received_today = imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
    

    不起作用,因为此时范围内没有imap,所以你会得到一个NameError。当你这样尝试时:

    @received_today = @imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
    

    您会收到 NoMethodError,因为实例变量(例如 @imap)在首次使用时会自动创建并初始化为 nil。你真正的@imap 在另一个对象中,所以你不能在其他任何地方将它称为@imap

    我认为你想要一个更像这样的结构:

    class User
        def imap
            if(!@imap)
                @imap = Net::IMAP.new('imap.gmail.com', 993, true, nil, false)
                # and presumably an @imap.authenticate too...
            end
            @imap
        end
    end
    
    class OtherOne
        def some_method(user)
            @today = Date.today
            @received_today = user.imap.search(["SINCE", @today.strftime("%d-%b-%Y")]).count.to_s
        end
    end
    

    将您的Net::IMAP 本地化在您的用户内部,并通过提供一个简单的访问器方法让其他对象使用它。

    哦,还有那个全局 $imap 的想法,我就假装我没看到,因为全局变量几乎总是一个非常糟糕的想法。

    【讨论】:

    • 谢谢!这是有道理的,所以基本上 User 类的实例作为参数传递给 OtherOne 类的 some_method,看起来像这样。我担心这样每次另一个类调用用户类时,Net::IMAP 都会登录并验证邮箱。如果许多其他类/方法不断尝试对邮箱“做事”并且每次都必须登录,似乎它可能会变慢。听起来,根据您的回答,没有办法只使用 net/IMAP 登录并保持打开状态。
    • @krapdagn: Net::IMAP.new 每个用户只会被调用一次,之后imap 只会返回现有的@imap。如果@imap 断开连接,您可能需要一些逻辑来重新连接。
    猜你喜欢
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 1970-01-01
    相关资源
    最近更新 更多