簡體   English   中英

如何在 Ruby 中使用全局變量

[英]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.

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