vieweditattachhistoryswikistopchangessearchhelp

特異クラス

Ruby で特異メソッドを登録しておく場所。移譲先。実行モデルには「特異クラス」というものはないらしい。(ん、これは実体がないということではなく、実体はあるが単にアクセスする手段が用意されていないということか?)--sumim
class << object
	self
end
のように記述して定義できる(実際には self のところに object にさせたい振る舞い等を記述する)。つまり特異メソッドをまとめて定義するためのものか?--sumim

疑問:

特異メソッドを持ったインスタンスのクラスは元の(つまりそのインスタンスを生み出すために new() したクラスのままか?--sumim

答え:

変わらずそのまま。
obj=Object.new
obj.class
==> Object

def obj.a
  "obj.a"
end

obj.a
==> "obj.a"
obj.class 
==> Object

class << obj
  attr :b, true
end

obj.b="obj.b"
obj.b
==> "obj.b"

obj2=Object.new
obj2.a
NameError: undefined method `a' for obj2

obj2.b
NameError: undefined method `b' for obj2
つまり、class << instance ... end でアクセスできるのは instance.class とは別のオブジェクト(おそらく無名のクラス)で、すなわちこれが特異クラスということか?--sumim

で、Ruby のクラスメソッドはクラスの特異メソッドなので、通常(Smalltalk で)はメタクラスがすることを特異クラスが担当しているというで「特異クラスはメタクラス」というような表現が使われることがあるということかしらん。ちなみに class() でアクセスできる(たとえば、Object.class )通常のクラスのクラス(メタクラスに相当)は Class である。--sumim

特異クラスは、まず直接アクセスしても、そうであるように表示されない。たとえば、Object のインスタンスの特異クラスは Object と表示される。また、class() 、type() は特異クラスをスキップして、特異クラスの class() 、type() を返す。したがって、このいずれかのルールにより、通常のクラスのクラスは(クラスの特異クラスのクラスである Class の名をかたった結果か、実際に自らのクラスである Class か、いずれにせよ)単に“Class”と表示する。


特異クラスにアクセスする方法


(Ruby Hacking Guide) クラスとモジュール [日本語] 特異クラスにアクセスする方法がある。
def inst_specific_class(obj)
  class << obj; self end
end

obj=Object.new
inst_specific_class(obj)==inst_specific_class(obj)
==> true

inst_specific_class(Object.new)==inst_specific_class(Object.new)
==> false

inst_specific_class(Object.new)==Object.new.class
==> false

inst_specific_class(Object)
==> Class   # Class の名をかたった Object の特異クラス

inst_specific_class(Object)==inst_specific_class(Object)
==> true

inst_specific_class(Object)==Object.class
==> false

これによると、クラスもやはり class() 、type() で特異クラスを返すのではなく、それをスキップして、そのまたクラスである Class を返している。

つまり戯さんが「シンプルだから、じゃないかな」の余談で言いたかったのはこういうことか。
ただ、この“パス”のしかたにはからくりがあって、インスタンスの特異クラスと、クラスの特異クラスで違うらしい。インスタンスの特異クラスでは、本来返すべき特異クラスのスーパークラスが返される。クラスの特異クラスでは、本来返すはずの特異クラスのクラスが返される。実験してみよう。
obj.class==inst_specific_class(obj).superclass
==> true

obj.class==inst_specific_class(obj).class
==> false

Integer.class==inst_specific_class(Integer).superclass
==> false

Integer.class==inst_specific_class(Integer).class
==> true
ビンゴ。いやぁ…(Smlaltalk ユーザーからすると)かなり変態的ですね。逆も真でお互い様(Ruby からしたら Smalltalk はかなり偏執的)だろうけど(と、いちおう Ruby ファン向けエクスキューズ)。--sumim


>実体がないということではなく、実体はあるが単にアクセスする手段が用意されていないということか?
>本来返すべき特異クラス
>本来返すはずの特異クラス
特異クラスの役割とか性質を考えると、本来、特異クラスを返すべきではないと思いますが。
例えば、特異クラスが返ってくる事によって、何か大きなメリットとかがあるのでしょうか。
それとは別に、特異クラス「を」返すような(トリッキーでない)関数なりメッセージなりが用意されていれば、いろいろ使い途があるとは思います。--CUE

class というメッセージは本来、レシーバがなんであれ、そのクラスを返すメッセージであるべきという意味で「本来」を使っています。--sumim



特異クラスのインスタンスを作る事って、できるんでしたっけ?
ちょっと手許に確かめる手段がないので、誰か代わりに試してくれる? --CUE

仮想クラスのインスタンスは作れないといったような例外を生じます。1.6.8 (2002-12-24) [arm-linux] + irb --sumim



質問投げてもいいっすか。「メソッドのクラス」という言葉がたびたび出てくるのですが、これは、「メソッドが定義されているクラス」という意味で、同様に「メソッドのスーパークラス」というのは、「メソッドが定義されているクラスのスーパークラス」という意味でよろしいでしょうか?--CUE

すみません、特異クラスを特異メソッドと打ち間違えていました(当該記述、修正しました)。え〜と、この修正で意味は通りますか? お手数でも今一度の読み直しをお願いします。ご指摘、ありがとうございます。--sumim

同様の記述ミスと思われる箇所は他にもあるのですが、勝手に直してみました。strike入れたとこがそうです。--CUE

恐縮です。ご修正いただいた通りです。どうも注意力散漫でいけませんね。お恥ずかしい。ちょっと読みにくかったので勝手ながら当該箇所は削除させていただきました。--sumim

このページを編集 (5519 bytes)


Congratulations! 以下の 4 ページから参照されています。

This page has been visited 5637 times.