classとStruct
RubyにはStructというクラスがある。
データを出し入れする専用のクラスを簡単に定義するためのものだ。
Hoge = Struct.new(:x, :y) foo = Hoge.new(5, 10) p foo.x # => 5 p foo.y # => 10 foo.x = 20 p foo.x # => 20
Struct.newすることで、その引数のattr_accessor指定シンボルを定義したようなサブクラスを生成する。
生成されたサブクラスの実体はクラスオブジェクトであり、ようするにクラスを生成するクラスで、メタプログラミングを活用した機能だ。
Hoge = Struct.new(:x, :y) p Hoge.class # => Class
ところでこのStruct、Rubyのソースを眺めているとCで書かれていて、なんだかちょっと高速に動かそうという努力の跡が見て取れる。
リファレンスを見ると便利ぽいメソッドもあるようだしその点でメリットが無いわけではないが、基本的にはattr_accessorだけ定義したクラスを作ればいいだけに、わざわざCで書いてあったりして実はちょー速いのではなかろうか、など思ったわけだ。
んで実験。Ruby1.9.1で試した。
require 'benchmark' class Hoge attr_accessor :data end Fuga = Struct.new(:data) Benchmark.bmbm { |x| x.report("class-new ") { 1000000.times { val = Hoge.new } } x.report("Struct-new") { 1000000.times { val = Fuga.new } } val = Hoge.new x.report("class-data= ") { 1000000.times { val.data = 0 } } val = Fuga.new x.report("Struct-data=") { 1000000.times { val.data = 0 } } }
気になる結果。
Rehearsal ------------------------------------------------ class-new 0.344000 0.000000 0.344000 ( 0.343750) Struct-new 0.781000 0.000000 0.781000 ( 0.796875) class-data= 0.360000 0.000000 0.360000 ( 0.359375) Struct-data= 0.343000 0.000000 0.343000 ( 0.359375) --------------------------------------- total: 1.828000sec user system total real class-new 0.344000 0.000000 0.344000 ( 0.343750) Struct-new 0.781000 0.000000 0.781000 ( 0.781250) class-data= 0.360000 0.000000 0.360000 ( 0.359375) Struct-data= 0.359000 0.000000 0.359000 ( 0.359375)
んんんんん?
Structのほうが生成に倍以上の時間がかかる上に、アクセスはほぼ同じ。ちなみにdataの取得も試したがどっちもほぼ同じ時間だった。1.8.7で動かしても傾向は同じ。
これは、なんというか。どうなん?