Ruby Language
暗黙的なレシーバと自己を理解する
サーチ…
常に暗黙の受信機があります
Rubyでは、すべてのメソッド呼び出しに常に暗黙のレシーバがあります。言語は、変数self
格納されている現在の暗黙受信者への参照を保持します。 class
やmodule
などの特定の言語キーワードは、 self
指すものを変更します。これらの動作を理解することは、言語をマスターする上で非常に役立ちます。
たとえば、 irb
を最初に開いたとき
irb(main):001:0> self
=> main
この場合、 main
オブジェクトは暗黙的な受信者です( main
についての詳細はhttp://stackoverflow.com/a/917842/417872を参照)。
def
キーワードを使用して、暗黙の受信側でメソッドを定義できます。例えば:
irb(main):001:0> def foo(arg)
irb(main):002:1> arg.to_s
irb(main):003:1> end
=> :foo
irb(main):004:0> foo 1
=> "1"
これは、あなたのreplで実行されているメインオブジェクトのインスタンスに対するメソッドfooを定義しています。
ローカル変数はメソッド名の前に検索されるので、同じ名前のローカル変数を定義すると、参照がメソッド参照よりも優先されることに注意してください。前の例から引き続き:
irb(main):005:0> defined? foo
=> "method"
irb(main):006:0> foo = 1
=> 1
irb(main):007:0> defined? foo
=> "local-variable"
irb(main):008:0> foo
=> 1
irb(main):009:0> method :foo
=> #<Method: Object#foo>
method
メソッドはfoo
メソッドを見つけることができます。なぜなら、ローカル変数をチェックするのではなく、通常の参照foo
がチェックするからです。
キーワードは暗黙の受信機を変更する
クラスまたはモジュールを定義すると、暗黙的な受信者はクラス自体への参照になります。例えば:
puts "I am #{self}"
class Example
puts "I am #{self}"
end
上記のコードを実行すると印刷されます:
"I am main"
"I am Example"
いつ自己を使用するのですか?
ほとんどのRubyコードは暗黙的な受信機を利用しているので、Rubyを初めて使うプログラマはしばしばself
いつ使うのか混乱します。実用的な答えは、 self
が2つの主要な方法で使われていることです。
1.受信機を変更する。
通常、クラスまたはモジュール内部のdef
の動作は、インスタンスメソッドを作成することです。自己を使ってクラスのメソッドを定義することができます。
class Foo
def bar
1
end
def self.bar
2
end
end
Foo.new.bar #=> 1
Foo.bar #=> 2
受信機の曖昧さを解消する
ローカル変数がメソッドと同じ名前を持つ場合、明確な受信者が曖昧さを排除する必要があります。
例:
class Example
def foo
1
end
def bar
foo + 1
end
def baz(foo)
self.foo + foo # self.foo is the method, foo is the local variable
end
def qux
bar = 2
self.bar + bar # self.bar is the method, bar is the local variable
end
end
Example.new.foo #=> 1
Example.new.bar #=> 2
Example.new.baz(2) #=> 3
Example.new.qux #=> 4
曖昧さ回避を必要とする他の一般的なケースでは、等号で終わるメソッドが必要です。例えば:
class Example
def foo=(input)
@foo = input
end
def get_foo
@foo
end
def bar(input)
foo = input # will create a local variable
end
def baz(input)
self.foo = input # will call the method
end
end
e = Example.new
e.get_foo #=> nil
e.foo = 1
e.get_foo #=> 1
e.bar(2)
e.get_foo #=> 1
e.baz(2)
e.get_foo #=> 2