【问题标题】:How to access a class variable from the outside in ruby?如何在 ruby​​ 中从外部访问类变量?
【发布时间】:2017-04-22 23:04:26
【问题描述】:

我正在尝试从类外的方法访问类变量。

这是我的课:

class Book

  @@bookCount = 0
  @@allBooks = []

  def self.allBooks
    @@allBooks
  end

  def self.bookCount
    @@bookCount
  end

  attr_accessor :name,:author,:date,:genre,:rating

  def initialize(name, author, date, genre, rating)
      @name = name
      @author = author
      @date = date
      @genre = genre
      @rating = rating
      @@bookCount += 1
      @@allBooks << self
  end

end

这是试图访问类变量@@bookCount的方法

def seeBookShelf
  if @@bookCount == 0
    puts "Your bookshelf is empty."
  else
    puts "You have " + @bookCount + " books in your bookshelf:"
    puts allBooks
  end
end

当我尝试执行该方法时,我得到了这个:

undefined local variable or method `bookCount' for main:Object (NameError)

如何从外部访问 bookCount?

【问题讨论】:

  • 第一个问题:为什么要使用类变量?这些在类和实例之间共享信息的方式通常会导致关注点的混淆。 self.class.allBooks 比直接访问要好。
  • Ruby 约定还强烈建议您以see_book_shelf 的风格命名事物,变量或方法名称中不要大写。类有混合大小写,领先的资本,就像你在这里。
  • 由于它保留了创建的任何 Book 实例的引用的方式,这基本上是在询问内存问题。您最好创建一个专门用于存储书籍的 BookShelf 类,而不是将此责任委托给 Book 的类级别。
  • 也许在 Book 类中定义VARIABLE = @@book_count,然后在类外使用Book::VARIABLE。但不确定这是否是推荐的技术,所以要小心。
  • @sagarpandya82 共享常量也是一件麻烦事。最好通过方法调用有一层薄薄的中介,这样您就可以有一些隔离,并且方法的实现可以在不破坏大量内容的情况下进行更改。

标签: ruby class-variables


【解决方案1】:

您可以使用class_eval 来评估特定类范围内的代码块:

class Book
  @@bookCount = 1
end

Book.class_eval '@@bookCount'
# => 1

而且只是为了好玩...您实际上可以用class_eval 做各种诡计,例如在类中定义一个新方法而无需猴子修补:

Book.class_eval { @@bookCount = 5 }
Book.class_eval '@@bookCount'
# => 5

Book.class_eval do
  def self.hey_look_a_new_method
    return "wow"
  end
end

Book.hey_look_a_new_method
# => "wow"

【讨论】:

    【解决方案2】:

    在大多数情况下,类实例变量优于类变量。后者在与继承一起使用时容易出现各种奇怪的行为。

    考虑:

    class Book
      @book_count = 0
      @all_books = []
    
      class << self
        attr_reader :book_count
        attr_reader :all_books
      end
    
      # further code omitted.
    
    end
    

    使用此代码 Book.book_count 和 Book.all_books 得到预期的数据。

    【讨论】:

      【解决方案3】:

      你需要一个 getter 来访问类变量,试试这个代码。 有关说明,请参阅http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/。 你也最好使用字符串插值,否则你会得到一个类型错误,而且它更 Rubyesque。

      class Book
        @@bookCount = 0
      
        def self.bookCount
          @@bookCount
        end
      end
      
      def seeBookShelf
        if Book.bookCount == 0
          puts "Your bookshelf is empty."
        else
          puts "You have #{Book.bookCount} books in your bookshelf:"
        end
      end
      
      seeBookShelf # Your bookshelf is empty.
      

      【讨论】:

      • 与@Gregory 的答案几乎相同。
      • 是的,我们同时提出,我喜欢尝试我的答案并将它们作为一个完整的可运行部分发布,通常然后我被更快的人击败,我认为我们的解决方案比伊利亚的,你试过吗?当 bookcount > 0 时注意到错误?
      【解决方案4】:

      使用class_variable_get 访问类外的类变量:

      class Foo
        @@a = 1
      end
      
      Foo.class_variable_get(:@@a)
      => 1
      

      【讨论】:

      • 技术上是正确的,但也是不明智的。 class_variable_get 方法用于反射目的,而不是通用编程。
      【解决方案5】:

      你必须指定变量的类:

      def seeBookShelf
        if Book.bookCount == 0
          puts "Your bookshelf is empty."
        else
          puts "You have " + Book.bookCount + " books in your bookshelf:"
          puts Book.allBooks
        end
      end
      

      【讨论】:

      • 不过,直接访问变量是一种不好的做法。你应该在你的类中添加吸气剂。或者创建一个新类 BookShelf 来存储你所有的书。
      • 如果这是在实例方法中,self.class 也适用于此。
      猜你喜欢
      • 2011-06-08
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      • 2013-07-08
      • 2012-09-03
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多