test.rb という名前の Ruby ファイルがあります。
ff="ff"
def test
puts ff
end
私はそれを実行し、エラーが発生しました:
test.rb:3:in `test': undefined local variable or method `ff' for main:Object (NameError)
これの理由は何ですか?それを説明するドキュメントはありますか?
test.rb という名前の Ruby ファイルがあります。
ff="ff"
def test
puts ff
end
私はそれを実行し、エラーが発生しました:
test.rb:3:in `test': undefined local variable or method `ff' for main:Object (NameError)
これの理由は何ですか?それを説明するドキュメントはありますか?
メソッド定義ff
内でアクセスできない理由は、(キーワードで作成された) メソッドが新しいスコープを作成するためです。それぞれキーワードとキーワードを使用してクラスとモジュールを定義する場合と同じです。test
def
class
module
(トップレベルのオブジェクト)の役割はmain
、この状況ではスコープの問題とはほとんど無関係です。
test
メソッドが定義コンテキストで定義されたローカルにアクセスできるようにしたい場合は、 define_method
(またはあなたの場合はdefine_singleton_method
メソッド)を使用してください。ここを参照してください。
ff = "hi"
define_singleton_method("test") { ff }
test #=> "hi"
def
キーワードとは異なり、define_method
メソッドのファミリは新しいスコープを作成しませんが、代わりに現在のスコープを閉じて、ローカル変数をキャプチャします。
@ff
@soup によって与えられた次の例でusing が機能した理由は、それmain
がどういうわけか「特別なケース」ではなく、トップレベルで定義された ivar が の ivar でありmain
、呼び出されたメソッドにアクセスできるためですmain
。
しかし、test
メソッドととの関係は何main
ですか? それ自体のメソッドでmain
はありません。実際には、 Object
クラスで定義されたプライベート インスタンス メソッドです。これは、そのtest
メソッドが (プライベート メソッドとして) Ruby プログラムのほぼすべてのオブジェクトで利用できることを意味します。最上位 ( main
) で定義されたすべてのメソッドは、実際にはObject
クラスのプライベート インスタンス メソッドとして定義されます。
Ruby トップレベルの詳細については、次の記事を参照してください: http://banisterfiend.wordpress.com/2010/11/23/what-is-the-ruby-top-level/
Ruby のスコープは単純でもあり複雑でもあります。
まず、すべてがオブジェクトであり、すべてにスコープがあることを覚えておく必要があります。
あなたの質問に直接答えるにmain
は、オブジェクトなどdef x...
です。オブジェクトのメソッドを定義しているときmain
pyr/irb で観察:
# note the error describes
[1] pry(main)> main 'main:Object'
NameError: undefined local variable or method 'main' for main:Object
from (pry):1:in '<main>'
# self is the current object, which is main
[2] pry(main)> self
=> main
# note main is an object of type Object
[3] pry(main)> self.class
=> Object
# main has methods
[4] pry(main)> self.methods
=> [:to_s, :public, etc etc]
だからあなたが書くとき
ff = "ff"
def test
puts ff
end
あなたが本当にしていることは
class main
ff = "ff"
def test
puts ff
end
end
ff
範囲外であるため、これは機能しません。これを修正するff
には、インスタンス変数に変換する必要があるため、その名前の前に@
. 以下が機能します。
@ff = "ff"
def test
puts @ff
end
test
これは、通常のクラスよりも特殊なケースのように思われることに注意してmain
ください。以下を参照してください。
独自のテストクラスがある場合:
class Test1
ff = "ff"
def test
puts ff
end
end
Test1.new.test # undefined variable/method 'ff' error
ff
期待どおりに正しいスコープで定義されていないため、これは失敗します。代わりに、パーサーがクラス宣言を実行しているときにスコープが設定されます。
それでは、上記の修正を試してみましょう。
class Test1Fixed
@ff = "ff"
def test
puts @ff
end
end
Test1Fixed.new.test # results in blank line
それは変だ。
このメソッドを追加しましょう:
def ff?
puts "ff is: #{@ff.nil? ? "nil" : "not nill"}"
end
Test1Fixed.new.ff? # => ff is: nil
なぜ @ff nil なのですか?
以下はこれをより明確にするかもしれません:
class Test2
puts "Where am i?"
@instance = "instance"
def initialize
puts "Initalize"
end
puts "pants on"
def test
puts "This will NOT output 'instance': #{@instance}"
end
def self.class_test
puts "This WILL output 'instance': #{@instance}"
end
end
puts "Creating new Test2 Object"
t = Test2.new
puts "Calling test on Test2 Object"
t.test
puts "Calling class_test on Test2 Class object"
Test2.class_test
これを実行すると、次の出力が得られます。
$ ruby scope.rb
Where am i?
pants on
Creating new Test2 Object
Initalize
Calling test on Test2 Object
This will NOT output 'instance':
Calling class_test on Test2 Class object
This WILL output 'instance': instance
ご覧のとおり、インターパーターは、他の場所と同様に、クラス宣言を順番に実行し、puts
ステートメントを出力します。メソッドの呼び出しを開始すると、これはさらに興味深いものになります。書く@instance = ...
ことは を書くことと同じなself.instance = ...
ので、インスタンスを定義した場所を推測できますか? はい、Test2 クラス オブジェクト (Test2 オブジェクトではありません) についてです。
これが、 を呼び出したときにtest
何も出力されない理由です。これは、内部の がインスタンス化されたオブジェクトtest
をself
参照しているためです (@instance を何かに設定した場所です!)。これが、実際のオブジェクトを指す内にインスタンス変数を設定する理由です。Test2
Test2 class object
initialize
self
を介してクラス メソッドを定義self.class_test
し、Test2 クラス オブジェクト ( Test2.class_test
) でそのメソッドを呼び出すと、予想される出力が得られることがわかります。これは、そのスコープで@instance
が定義されているためです。
これが何らかの意味を持っていることを願っています。
http://rubykoans.com/スコープ セクションは、この知識の一部を固めるのに役立つ場合があります。
Ruby では、シジルのない名前には常に「ローカル」スコープがあります。Ruby は字句スコープを使用するため、メソッド内では、名前は常にそのメソッドのみを参照します。
他のスコープは、グローバル、インスタンス、およびクラスです。それらについての良いドキュメントがあります: http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Operators#Scope
問題を解決するにはいくつかの方法があります。私のお気に入りは、印刷されているものを引数として渡すことです。
ff = "ff"
def test(ff)
puts ff
end
おそらく、クラスで行っていることは何でもカプセル化し、インスタンス変数を使用するでしょう。
グローバル変数 ($ff) を使用することもできますが、その方法は狂気です。
Ruby でメソッド内のローカル変数にアクセスできないのはなぜですか?
ローカル変数だからです。ローカル変数は、それらが定義されているスコープに対してローカルです。それが、結局、「ローカル変数」と呼ばれる理由です。
この場合、スクリプト スコープでローカル変数を定義したため、それはスクリプト スコープで表示され、それ以外の場所では表示されません。