Cum să accesați o variabilă de clasă din exterior în ruby? (Programare, Ruby, Variabile De Clasă)

winterwolff a intrebat.

Încerc să accesez o variabilă de clasă dintr-o metodă din afara clasei.

Aceasta este clasa mea:

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

Aceasta este metoda care încearcă să acceseze variabila de clasă @@bookCount

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

Când încerc să execut metoda obțin următorul lucru:

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

Cum pot accesa bookCount din exterior?

Comentarii

  • Prima întrebare: De ce folosiți variabile de clasă? Acestea partajează informații între clasă și instanțe într-un mod care duce adesea la o confuzie a preocupărilor. self.class.allBooks este mai bună decât accesarea directă a acesteia. –  > Por tadman.
  • De asemenea, convențiile Ruby recomandă cu tărie să denumiți lucrurile în stilul see_book_shelf fără majuscule în numele variabilelor sau al metodelor. Clasele au majuscule mixte, cu majusculă înainte, așa cum aveți aici. –  > Por tadman.
  • Din cauza modului în care acest lucru păstrează referințele oricărei instanțe de Book create, acest lucru este practic o cerere de probleme de memorie. Ar fi mai bine să creați o clasă BookShelf, care este destinată în mod special stocării cărților, decât să delegați această responsabilitate la nivelul clasei Book. –  > Por tadman.
  • Poate definiți VARIABLE = @@book_count în clasa Book, apoi utilizați Book::VARIABLE în afara clasei. Dar nu sunt sigur că aceasta este o tehnică recomandată, așa că fiți atenți. –  > Por iceツ.
  • @sagarpandya82 Împărtășirea constantelor este, de asemenea, o afacere murdară. Este mai bine să aveți un strat subțire de intermediere prin intermediul unui apel de metodă, astfel încât să aveți o oarecare izolare și implementarea metodei să se poată schimba fără a sparge tone de lucruri. –  > Por tadman.
5 răspunsuri
Ilya

Utilizați class_variable_get pentru a accesa o variabilă de clasă în afara unei clase:

class Foo
  @@a = 1
end

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

Comentarii

  • Corect din punct de vedere tehnic, dar, de asemenea, nerecomandat. class_variable_get este destinată scopurilor de reflecție, nu programării generale. –  > Por tadman.
Peter Camilleri

În majoritatea cazurilor, variabilele de instanță de clasă sunt preferate variabilelor de clasă. Acestea din urmă sunt predispuse la tot felul de comportamente ciudate atunci când sunt utilizate cu moștenirea.

Luați în considerare:

class Book
  @book_count = 0
  @all_books = []

  class << self
    attr_reader :book_count
    attr_reader :all_books
  end

  # further code omitted.

end

Cu acest cod, Book.book_count și Book.all_books obțin datele așteptate.

Mike S

Puteți utiliza class_eval pentru a evalua un bloc de cod în cadrul domeniului de aplicare al unei clase specifice:

class Book
  @@bookCount = 1
end

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

Și doar pentru distracție… puteți face tot felul de trucuri cu class_eval cum ar fi definirea unei noi metode în clasă fără a face un patch de maimuță:

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"

user6225298

Trebuie să specificați clasa variabilei :

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

Comentarii

  • Cu toate acestea, accesarea directă a variabilelor este un mod greșit de a face acest lucru. Ar trebui să adăugați getters în clasa dvs. Sau creați o nouă clasă BookShelf pentru a stoca toate cărțile dvs. – user6225298
  • self.class funcționează și aici dacă aceasta se află într-o metodă de instanță. –  > Por tadman.
peter

Aveți nevoie de un getter pentru a accesa variabila de clasă, încercați acest cod.Vedeți http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ pentru o explicație.De asemenea, este mai bine să folosiți interpolarea șirurilor de caractere, altfel veți obține o eroare de tip, de asemenea, este mai 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.

Comentarii

  • aproape același răspuns ca și @Gregory. –  > Por Ilya.
  • Da, am răspuns în același timp, îmi place să încerc răspunsurile mele și să le public ca o întreagă piesă executabilă, de multe ori atunci sunt bătut de cineva mai rapid, cred că soluția noastră este mai bună decât cea a lui Ilya, le-ați încercat ? ați observat eroarea când bookcount > 0 ? –  > Por peter.