web-dev-qa-db-ja.com

Rubyローカル変数は未定義

私は次のRubyコードを持っています:

local_var = "Hello"

def hello
  puts local_var
end

hello

次のエラーが表示されます。

local_variables.rb:4:in 'hello': undefined local variable or method 'local_var' 
for main:Object (NameError) from local_variables.rb:7:in '<main>'

ローカル変数は、ブロック、関数、クロージャなどの外部からアクセスできないといつも思っていました。

しかし今、私はファイルにローカル変数を定義し、関数[〜#〜] inside [〜#〜]同じファイルからアクセスしようとしました。

私の理解の何が問題になっていますか?

37
Sergii Shevchyk

In Rubyローカル変数は、それらが定義されたスコープでのみアクセス可能です。クラス、モジュール、またはメソッドを入力/脱退するたびに、Rubyでスコープが変更されます。

例えば ​​:

v1 = 1

class MyClass # SCOPE GATE: entering class
  v2 = 2
  local_variables # => ["v2"]

  def my_method # SCOPE GATE: entering def
    v3 = 3
    local_variables  # => ["v3"]
  end # SCOPE GATE: leaving def

  local_variables # => ["v2"]
end # SCOPE GATE: leaving class

これらの出入りポイントは、スコープゲートと呼ばれます。メソッド定義を介してScope Gateから入力するため、helloメソッド内でlocal_varにアクセスできません。


Scope Flatteningコンセプトを使用して、変数をこれらのゲートに渡すことができます。

たとえば、メソッドの定義にdefを使用する代わりに、Module#define_methodを使用できます。

local_var = "Hello"

define_method :hello do
  puts local_var
end

同様に、Class#Newを介してクラスを定義できるため、クラス定義を渡すときにスコープが変更されません。

local_var = 'test'

MyClass = Class.new do
  puts local_var #valid
end

の代わりに

class MyClass
  puts local_var #invalid
end

同様に、モジュールゲートを介してローカル変数を渡す場合は、Module#Newを使用する必要があります。

Metaprogramming Ruby からの例

55