跨类的ruby变量作用域



RuNubie点击此处。我有一个类Login,它使用net/IMAP库登录到gmail。正在发生的事情是,我创建了该类的一个新实例,例如:

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

然后,我正在学习其他课程,这些课程将对邮箱做一些"事情"。问题是我在Login中定义的@imap变量似乎已经消失了(我认为是由于作用域)。

以下是在Login类中声明@imap的方式:@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是一种糟糕的做法吗?太困惑了,我敢打赌答案也很简单明了,但我就是看不出来。谢谢!

这:

@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本地化到User中,并通过提供一个简单的访问器方法让其他对象使用它。

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

在User类中定义imap变量的一种较短方法,与mu发布的内容基本相同:

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

最新更新