字句スコープとRubyクラス変数
Rubyのクラス変数は紛らわしいです。熟練したRubyユーザーでさえ、直感的に理解するのが難しい場合があります。最も明白な例は、継承と関係があります:
class Fruit
@@kind = nil
def self.kind
@@kind
end
end
class Apple < Fruit
@@kind = "apple"
end
Apple.kind
# => "apple"
Fruit.kind
# => "apple"
kind
の変更 子クラスの変数は、親クラスでも変更します。それはかなりめちゃくちゃです。しかし、これはまさにその言語が機能することになっている方法です。 Smalltalkを模倣することは、ずっと前に行われた設計上の決定でした。
クラス変数の奇妙さの他の例は、実装の癖ほどアーキテクチャ上の選択ではないようです。今日は、私が面白いと思うこれらの1つについて少しお話します。
次に、2つのコードを比較します。それらは同じ結果を生成するはずのように見えますが、そうではありません。
最初の例では、クラス変数を設定し、それを返すメソッドを作成します。ここでは何も派手なことはありません。そして、すべてが期待どおりに機能します。
class Foo
@@val = 1234
# This is shorthand for declaring a class method.
class << self
def val
@@val
end
end
end
Foo.val
# => 1234
おそらくあなたはこれを知らなかったでしょうが、class << self
クラス定義内にある必要はありません。以下の例では、それを外部に移動しました。クラスメソッドが追加されましたが、クラス変数にアクセスできません。
class Bar
@@val = 1234
end
class << Bar
def val
@@val
end
end
Bar.val
# warning: class variable access from toplevel
# NameError: uninitialized class variable @@val in Object
関数からクラス変数にアクセスしようとすると、警告と例外が発生します。何が起こっているのですか?
語彙スコープがRubyの奇妙で紛らわしい側面の99%の原因であると私はますます確信するようになっています。
この用語に精通していない場合、字句スコープとは、抽象オブジェクトモデルのどこに属するかではなく、コード内のどこにあるかに基づいて物事をグループ化することを指します。例を示すだけの方がはるかに簡単です:
class B
# x and y share the same lexical scope
x = 1
y = 1
end
class B
# z has a different lexical scope from x and y, even though it's in the same class.
z = 3
end
では、クラス変数の例では、字句スコープはどのように機能していますか?
クラス変数を取得するには、Rubyはどのクラスから取得するかを知っている必要があります。字句スコープを使用してクラスを検索します。
実際の例を詳しく見ると、クラス変数にアクセスするコードが物理的にクラス定義に含まれていることがわかります。
class Foo
class << self
def val
# I'm lexically scoped to Foo!
@@val
end
end
end
動作しない例では、クラス変数にアクセスするコードは、字句的にクラスにスコープされていません。
class << Bar
def val
# Foo is nowhere in sight.
@@val
end
end
しかし、それが語彙的にクラスにスコープされていない場合、それは何にスコープされますか? Rubyが出力する警告は、私たちに手がかりを与えます:warning: class variable access from toplevel
。
動作しない例では、クラス変数が字句的に最上位オブジェクトにスコープされていることがわかります。これにより、非常に奇妙な動作が発生する可能性があります。
たとえば、字句スコープがmainにあるコードからクラス変数を設定しようとすると、クラス変数はObject
に設定されます。 。
class Bar
end
class << Bar
def val=(n)
# This code is lexically scoped to the top level object.
# That means, that `@@val` will be set on `Object`, not `Bar`
@@val = i
end
end
Bar.val = 100
# Whaa?
Object.class_variables
# => [:@@foo]
クラスの字句スコープ外でクラス変数を参照する方法はたくさんあります。それらのすべてはあなたに問題を与えるでしょう。
ここにあなたの楽しみのためのいくつかの例があります:
class Foo
@@foo = :foo
end
# This won't work
Foo.class_eval { puts @@foo }
# neither will this
Foo.send :define_method, :x do
puts @@foo
end
# ..and you weren't thinking about using modules, were you?
module Printable
def foo
puts @@foo
end
end
class Foo
@@foo = :foo
include Printable
end
Foo.new.foo
そして今、あなたは誰もがRubyでクラス変数を決して使用しないと言う理由を知っています。 :)
-
Rubyで環境変数を使用する方法
環境変数はキーと値のペアであり、次のようになります。 KEY=VALUE これらの変数を使用して、コンピューター内のすべてのプログラム間で構成オプションを共有します。 そのため、それらがどのように機能するか、およびENVを使用してRubyプログラムからそれらにアクセスする方法を学ぶことが重要です。 特別な変数。 環境変数の例 : デフォルトのエディターの構成 宝石の場所をRubyに伝える(GEM_PATH / GEM_HOME ) APIキーを、ソース管理(git)にコミットせずにアプリケーションに渡す オペレーティングシステムがバイナリファイル(Windowsでは.exe)を検
-
Rubyのデコレータデザインパターン
デコレータのデザインパターンは何ですか? そして、Rubyプロジェクトでこのパターンをどのように使用できますか? デコレータデザインパターンは、新機能を追加することでオブジェクトを強化するのに役立ちます クラスを変更せずにそれに。 例を見てみましょう! ロギングとパフォーマンス この例では、rest-clientのようなgemを使用してHTTPリクエストを作成しています。 次のようになります: require restclient data = RestClient.get(www.rubyguides.com) 今 : 一部のリクエストにログを追加したいが、RestCli