[英]How to use global variables in Ruby
我有一種情況,我在腳本頂部定義了一個變量,並希望在方法中引用它:
#############
# Variables #
#############
tmp_dir = '/path/to/tmp/dir'
###########
# Methods #
###########
def cache(page)
begin
%x[wget -q -O #{tmp_dir}/page #{page}]
rescue => msg
puts "error: #{msg}"
exit
end
end
cache("http://somepage.com")
我收到此錯誤:
undefined local variable or method `tmp_dir' for main:Object
我猜我需要讓tmp_dir
成為一個全局變量? 我討厭使用全局變量。 有沒有 Ruby-ish 的方法來做到這一點?
tmp_dir
在類定義中被定義為變量,但在實例函數中,您正在尋找在類的實例上定義的tmp_dir
。 這就是為什么tmp_dir
在函數內未定義的原因。
您可以將其設為全局或將其設為類變量作為快速修復。 我認為有一個更好的選擇:將其包裝在知道如何緩存的自己的類中,然后初始化tmp_dir
而不將其設為全局或類變量:
class Cacher
def initialize(tmp_dir)
@tmp_dir = tmp_dir
end
def cache(page)
wget "#{@tmp_dir}/page"
end
end
# in your main file:
cacher = Cacher.new('/path/to/tmp/dir') # here's your configuration line, but with no global!
# later
cacher.cache("index.html")
你是對的。 應避免使用全局變量。 自然的選擇是類上的實例變量或常量。
在您的情況下,您似乎在整個腳本執行過程中都有一些不會改變的東西。 那么,一個常數是最合適的。 您可以在適當的模塊中定義此常量。
TmpDir = "/path/to/tmp/dir"
還要注意,Ruby 有一種內置的方式來引用 tmp 目錄。
require "tmpdir"
Dir.tmpdir # => "/tmp" (depending on the environment)
你是對的。 您需要通過在變量前面加上$
來使變量成為全局變量。 前任:
$tmp_dir = '/path/to/tmp/dir'
除了這樣做之外,您還可以將其設為實例變量,或者您可以重構以使其成為一個類。 我建議按照萊利·拉克 (Riley Lark) 所說的去做。
除了其他答案之外,要使在類定義范圍中設置的局部變量在方法定義中起作用,您可以使用define_method
,它是一種采用塊的方法。 Ruby
中的塊是閉包,因此它們與設置它們的環境一起使用:
define_method(:cache) do |page|
begin
%x[wget -q -O #{tmp_dir}/page #{page}]
rescue => msg
puts "error: #{msg}"
exit
end
end
簡答
聽起來您正在編寫一個簡短的腳本。 如果是這種情況,您沒有理由不能使用像$tmp_dir
這樣的可修改全局變量。 但是如果你不需要修改它,你應該使用TMP_DIR
的全局常量的解決方案,比如TMP_DIR
。 在這種情況下,您應該在字符串上調用.freeze
以避免意外修改。
更長的答案
如果腳本變得更長或更復雜,您應該重構為類。 在這種情況下, TMP_DIR
解決方案仍然有效。 但是如果你需要修改這個值,你可以創建一個ConfigObject
類來對這些變量進行分組。
例子:
ConfigObject = Struct.new(:tmp_dir, :file_limit)
# it's a good idea to create this before everything else
$config = ConfigObject.new('/tmp/dir', 10)
class Foo
def do_something
$config.file_limit # use this somehow
$config.file_limit = 5 # change
end
end
類似的技術使用類變量來完成相同的事情:
class ConfigObject
class << self
attr_accessor :tmp_dir, :file_limit
end
@tmp_dir = '/tmp/dir'
@file_limit = 10
end
class Foo
def do_something
ConfigObject.file_limit # use this somehow
ConfigObject.file_limit = 5 # change
end
end
將ConfigObject
視為其他類使用的“服務”。 如果您的應用程序變得復雜到需要多個交互服務,您可能需要設置一種服務注冊表來保存對服務的引用(谷歌“依賴注入”了解更多信息)。
注意:您不應該將您的類命名為Config
因為它已經是一個內置類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.