簡體   English   中英

在Ruby 1.9中訪問類變量的正確方法是什么?

[英]What is the proper way to access class variables in Ruby 1.9?

我正在嘗試設置一些類變量來存儲Rails應用程序中的路徑(但我認為這更像是一個紅寶石問題)

基本上我的班級看起來像這樣

class Image < ActiveRecord::Base

   @@path_to_folder = "app/assets"
   @@images_folder = "upimages"
   @@path_to_images = File.join(@@path_to_folder, @@images_folder)

end

但是當我嘗試通過執行Image.path_to_images從我的控制器訪問@@path_to_images ,我得到一個NoMethodError

當我嘗試使用Image.class_eval( @@path_to_images ) ,我uninitialized class variable @@path_to_images in ImagesController獲得了uninitialized class variable @@path_to_images in ImagesController

我已經四處尋找,我所看到的一切都說會有用,所以我對此非常困惑

更重要的是,我嘗試使用ruby控制台來定義簡單的類

 class Bidule
     @@foo = "foo"
     Bar = "bar"
 end

因此,我認為,我嘗試了所有可能的方式(包括前2個)來訪問它們,但我總是得到一個例外

Rails為此功能提供類級別屬性訪問器

嘗試

class Image < ActiveRecord::Base
  cattr_accessor :path_to_folder
  @@path_to_folder = "app/assets"
end

然后訪問path_to_folder類變量就可以了

Image.path_to_folder

但人們總是建議避免類變量,因為它在繼承中的行為。所以你可以使用像常量這樣的常量

class Image < ActiveRecord::Base
   PATH_TO_FOLDER = "app/assets"
end

然后你就可以訪問常量了

Image::PATH_TO_FOLDER

雖然我一般不會推薦它,但您可以通過將字符串傳遞給class_eval來訪問類變量,如下所示:

Image.class_eval('@@path_to_folder')

至少在Ruby的更高版本中。

但請注意,類變量與子類層次結構中最高級的類相關聯。 對於像這樣的ActiveRecord子類,這意味着這些類變量確實存在於ActiveRecord::Base的命名空間中。

如果您不能或不想擴展類使用:

Image.class_variable_get(:@@path_to_images)

類變量在Ruby應用程序中很少使用,因為它們有很多限制,並且往往會違反適當的面向對象設計。

幾乎在每種情況下,類變量都可以用適當的常量,類方法或兩者替換。

您的示例可能更好地描述為:

class Image < ActiveRecord::Base
  PATH_TO_FOLDER = "app/assets"
  IMAGES_FOLDER = "upimages"
  PATH_TO_IMAGES = File.join(PATH_TO_FOLDER, IMAGES_FOLDER)
end

類變量對於所討論的類是私有的,並且不會滲透到子類,並且難以從外部上下文訪問。 使用常量允許使用以下內容:

image_path = Image::PATH_TO_FOLDER

在某些情況下,類變量比替代方案更合理,但這些通常非常罕見。

最好的方法是使用方法設置和獲取值。 下面是一個示例代碼

class Planet
  @@planets_count = 0

  def initialize(name)
    @name = name
    @@planets_count += 1
  end

  def self.planets_count
    @@planets_count
  end  

  def self.add_planet
    @@planets_count += 1
  end

  def add_planet_from_obj
    @@planets_count += 1
  end
end


Planet.new("uranus")
Plant.add_planet
obj = Planet.new("earth")
obj.add_planet_from_obj

您可以通過將其包裝在類方法中來實現,如下所示:

def self.path_to_images
  @@path_to_images
end

但我應該提一下,你應該盡量避免在rails中使用類變量

我會像這樣修改它:

class Image < ActiveRecord::Base

  @@path_to_folder = "app/assets"
  @@images_folder = "upimages"
  @@path_to_images = File.join(@@path_to_folder, @@images_folder)

  def initialize
  end 
  ...
  def self.path_to_folder
    @@path_to_folder
  end
end

你在這里做的是將類變量變成一個方法,所以你現在可以訪問使用.method名稱調用。 因為這是一個類變量,所以你只能在類本身上調用它,而不能在類的實例上調用它。 你得到一個'NoMethodError',因為你使用一個不存在的方法調用類變量。 上面的代碼在你說的行上定義了這個方法:

def self.path_to_folder
  @@path_to_folder
end

這將現在有效:

Image.path_to_folder

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM