Ruby お勉強の自分用メモ
インスタンス変数
インスタンスごとに異なる値を持つ変数
@
から始まる変数名で定義する
インスタンス変数はデフォルトでは外部からアクセスすることはできない、
アクセス可能にするにはアクセサの属性を設定する必要がある
class Todo def initialize(task, limit) # インスタンス変数 @task = task @limit = limit end def display "#{@task}: limit: #{@limit}" end end todo01 = Todo.new('Taks01', '2019-11-10') todo02 = Todo.new('Taks02', '2019-11-20') puts todo01.display # => "Taks01: limit: 2019-11-10" puts todo02.display # => "Taks01: limit: 2019-11-20" # 外部から直接インスタンス変数にアクセスする際はできない todo01.@task # => syntax error # アクセサが設定されていないのでインスタンス変数に触ることはできない todo01.task # => NoMethodError: undefined method `task` # アクセサを設定 class Todo attr_accessor :task end # アクセサ (getter) が設定されたインスタン変数にはアクセス可能になる p todo01.task # => "Taks01"
アクセサ属性
キーワードにインスタンス変数名をシンボルの形式で渡すことで設定
attr_accessor
... getter , setter を設定attr_reader
... getter のみを設定attr_writer
... setter のみを設定
class Idol attr_reader :name attr_writer :type attr_accessor :rank def initialize(name, type, rank = 100) @name = name @type = type @rank = rank end def display puts "#{@name} (#{@type}) Rank: #{@rank}" end end aoi = Idol.new('Kiriya Aoi', 'cool') aoi.display # => "Kiriya Aoi (cool) Rank: 100" # attr_accessor は読み書き可能 p aoi.rank # => 100 aoi.rank = 3 p aoi.rank # => 3 # 設定されていない getter, setter を使おうとするとエラー # attr_reader は getter のみ p aoi.name # => "Kiriya Aoi" aoi.name = 'Hoshimiya Ichigo' # => NoMethodError: undefined method `name=' # attr_writer は setter のみ p aoi.type # => NoMethodError: undefined method `type' for aoi.type = 'pop' aoi.display # => Kiriya Aoi (pop) Rank: 3
attr_accessor
の設定は下記の様に独自にgetter, setter を設定するのと同等
class Foo def initialize(name = 'foo') @name = name end # getter def name @name end # setter def name=(val) @name = val end end foo = Foo.new p foo.name # => "foo" foo.name = 'bar' p foo.name # => "bar"
インスタンス変数は値がセットされて始めて生成される
class Idol attr_accessor :name def my_name_is(name) @name = name end end hoshimiya = Idol.new # 値がセットされていない状態では存在しない扱い p hoshimiya.instance_variables # => [] p hoshimiya.name # => nil hoshimiya.my_name_is 'Ichigo' p hoshimiya.instance_variables # => [:@name] p hoshimiya.name # => "Ichigo"
アクセサの状態とインスタンス変数のアクセス可能な方法の違い
getter, setter の有無によってインスタンス変数にアクセス可能な表記とアクセスできない表記がある
class Hoo attr_accessor :read_get_var attr_reader :read_only_var attr_writer :write_only_var def initialize @read_get_var = "has_accessor" @read_only_var = "has_rader" @write_only_var = "has_writer" @no_accessor = "no_accessor" end def call_by_at p @read_get_var # => "has_accessor" p @read_only_var # => "has_rader" p @write_only_var # => "has_writer" p @no_accessor # => "no_accessor" end def call_by_self p self.read_get_var # => "has_accessor" p self.read_only_var # => "has_rader" # getter メソッドの呼び出しになるのでエラーになる p self.write_only_var # => NoMethodError: undefined method `write_only_var` p self.no_accessor # => NoMethodError: undefined method `no_accessor` end def call_by_no_recever p read_get_var # => "has_accessor" p read_only_var # => "has_rader" # getter メソッドの呼び出しになるのでエラーになる p write_only_var # => NameError: undefined local variable or method `write_only_var` p no_accessor # => NameError: undefined local variable or method `no_accessor` end end hoo = Hoo.new # `@変数名` でアクセス hoo.call_by_at # `self.変数名` でアクセス hoo.call_by_self # `変数名` でアクセス hoo.call_by_no_recever
メソッド内で @
無しの変数名でのアクセスは、self
の省略形になるので、self.変数名
と同じ結果になる
インスタンス変数はクラスからはアクセスできない
インスタンス変数は、アクセサを設定してもクラスからはアクセスできない
class Bar attr_accessor :my_name def initialize @my_name = 'bar' end end bar = Bar.new p bar.my_name # => 'bar' Bar.my_name # => NoMethodError: undefined method `my_name' for Bar:Class
クラスメソッドのを作成してもインスタンス変数はインスタンスごとに異なる値を持つのでアクセスできない
class Bar attr_accessor :my_name def initialize @my_name = 'bar' end def self.my_name @my_name end end p Bar.my_name # => nil
クラス変数
@@
で始まる変数名で定義する
クラス変数は、クラスと子孫クラス・それらのクラスのインスタンス変数で共有される
クラス変数にはアクセサ属性が適応できないので、getter, setter は独自に設定する必要がある
class Foo @@class_name = 'foo' def display puts "#{self.class} class_name is #{@@class_name}" end end class Bar < Foo # instance getter def class_name @@class_name end # instance setter def class_name=(val) @@class_name = val end end class Baz < Foo # class getter def self.class_name @@class_name end # class setter def self.class_name=(val) @@class_name = val end end foo = Foo.new bar = Bar.new baz = Baz.new foo.display # => Foo class_name is foo bar.display # => Bar class_name is foo baz.display # => Baz class_name is foo bar.class_name = 'bar' p bar.class_name # => "bar" foo.display # => Foo class_name is bar bar.display # => Bar class_name is bar baz.display # => Baz class_name is bar p Baz.class_name # => "bar" Baz.class_name = "xxx" p Baz.class_name # => "xxx" p bar.class_name # => "xxx" foo.display # => Foo class_name is xxx bar.display # => Bar class_name is xxx baz.display # => Baz class_name is xxx # getter, setter を設定してないと外部からインスタンス変数同様アクセスできない Foo.class_name # => NoMethodError: undefined method `class_name` foo.class_name # => NoMethodError: undefined method `class_name`
クラス変数はインスタンスメソッド内でも定義できるが、メソッドを通って値が渡されるまでクラス変数は設定されない
class Hoo def initialize @@class_name = 'hoo!' end def self.class_name @@class_name end end p Hoo.class_name # => NameError: uninitialized class variable @@class_name in Hoo p Hoo.class_variables # => [] hoo = Hoo.new Hoo.class_name # => "hoo!" Hoo.class_variables # => [:@@class_name]
継承させた子孫クラスでも同様
class Xoo < Hoo @@xoo_var = 'xoo' def self.xoo_var @@xoo_var end end # クラス変数に値が設定されていない状態だとエラー Xoo.class_name # => <NameError: uninitialized class variable @@class_name in Hoo xoo = Xoo.new # 親クラスのクラス変数に子孫クラスで値が設定されれば親クラスでも値が設定されている p Hoo.class_name # => "hoo!" p Hoo.class_variables # => [:@@class_name] p Xoo.class_name # => "hoo!" # 但し子孫クラスに設定されたクラス変数は親クラスでは参照できない Xoo.xoo_var # => "xoo" Hoo.xoo_var # => NoMethodError: undefined method `xoo_var`
クラスインスタンス変数
クラスインスタンス変数は変数が設定されたクラスからのみ参照できる変数で、クラスのインスタンスや子孫クラスからは参照できない
変数名は @
から始めクラス定義はclass式内のトップレベルまたはクラスメソッド内に定義する (※ 通常のメソッド内で定義するとインスタンス変数になる)
クラスインスタンス変数は、クラス変数と同様でアクセサは自前で実装する必要がある
class CuteIdol # クラスインスタンス変数 @type = 'cute' def initialize(name) # メソッド内で定義するとインスタンス変数になる @name = name end def say_my_type # クラスインスタンス変数はインスタンスからもアクセスできない p @type # => nil end def display # クラスからのみアクセスができるので `クラス名.クラスインスタンス変数名` でアクセスができるがgetterが無いと例外が発生する # self.type は getter があっても例外になるので注意! puts "#{@name} type is #{CuteIdol.type}!" end def self.display # クラスメソッドでは `@変数名` でアクセスが可能 puts "#{self} Class type is #{@type}" end end CuteIdol.display # => CuteIdol Class type is cute p CuteIdol.instance_variables # => [:@type] ichigo = CuteIdol.new('Hoshimiya Ichigo') # クラスのインスタンスからもはアクセスできない ichigo.say_my_type # => nil # getter が無いと NoMethodError ichigo.display # => NoMethodError: undefined method `type` class CuteIdol def self.type @type end def self.type=(val) @type = val end end ichigo.display # => Hoshimiya Ichigo type is cute!
クラスメソッド内で定義
class Xoo def self.init @xoo = 'xoo' end def self.xoo @xoo end def xoo @xoo end end xoo = Xoo.new Xoo.init p Xoo.xoo # => xoo p xoo.xoo # => nil class Zoo < Xoo end p Zoo.xoo # => nils
クラスインスタンス変数は子孫クラスからもアクセスできない
class Foo @class_name = 'foo' def self.display puts "#{self} name is #{@class_name}" end def self.class_name @class_name end end class Hoo < Foo def self.hi p @class_name end end Foo.display # => "Foo name is foo" p Foo.class_name # => "foo" p Foo.instance_variables # => [:@class_name] Hoo.display # => Hoo name is Hoo.hi # => nil p Hoo.class_name # => nil p Hoo.instance_variables # => []
クラス定数
class式内のトップレベルに大文字から始まる変数を定義するとクラス定数になる
クラス定数は子孫クラスからもアクセス可能
定数なので変更しようとすると warning が発生する
class StarLightStudent SCHOOL_NAME = 'StarLight' attr_reader :name def initialize(name) @name = name end def display puts "#{@name} - #{SCHOOL_NAME} Scholl" end end class Idol < StarLightStudent def initialize(name, type) super name @type = type end def display puts "#{@name} (#{@type}) - #{SCHOOL_NAME} Scholl" end end p StarLightStudent::SCHOOL_NAME # => "StarLight" akari = StarLightStudent.new('Ozora Akari') akari.display # => "Ozora Akari - StarLight Scholl" ichigo = Idol.new('Hoshimiya Ichigo', 'cute') ichigo.display # => "Hoshimiya Ichigo (cute) - StarLight Scholl"
クラス定数に外部からアクセスするには getter を独自に作成する必要がある
setter を定義すると warning が発生する
class Week DAY_OF_WEEK = 7 def self.DAY_OF_WEEK DAY_OF_WEEK end def self.DAY_OF_WEEK=(val) DAY_OF_WEEK = val # => dynamic constant assignment end end p Week.DAY_OF_WEEK # => 7 # warning が発生するが値の更新は可能 Week::DAY_OF_WEEK = 3 # warning: already initialized constant Week::DAY_OF_WEEK p Week.DAY_OF_WEEK # => 3
トップレベルに定義された定数は Object
のクラス定数として定義される
HOGE = 'hoge!' p Object::HOGE # => "hoge!" class Hoge HOGE = 'fugafuga' def say p HOGE # => "fugafuga" # トップレベルの定数を参照する p Object::HOGE # => "hogehoge!" end end Hoge.new.say
クラスの定義は、クラスを表す Class クラスのインスタンスを作成し、そのインスタンスを参照するクラス名の定数を作成するので、クラス名と定数名が被っているとエラーになる
HOGE = 'hoge!' class HOGE end # => HOGE is not a class (TypeError)
まとめ
- インスタンス変数はクラス内のメソッドで使う時は
@変数名
にしておけば間違いなさそう - クラス内に作れる変数は、外部からアクセスするには基本的にアクセサが必要
インスタンス変数はattr_
でアクセサを作成することができるが、それ以外は独自に必要なメソッドを作成する必要がある - インスタンス変数は
@
で始まる変数名でメソッド内に定義
変数定義は子孫クラスにも引き継がれインスタンスごとに異なる値を持つのでインスタンスからのみアクセス可能
インスタンス変数は、値がセットされて始めて生成される - クラス変数は
@@
で始まる変数名で定義・クラス定数は 大文字から始まる変数名で定義
クラス変数・クラス定数は、クラスと子孫クラス、それらのインスタンスから参照できる - クラスインスタンス変数は
@
で始まる変数名で class式内のトップレベルまたは、クラスメソッド内に定義 クラスインスタンス変数は、変数の定義されたクラスからのみ参照可能 - クラス定義はトップレベルに定数として定義される
![初めてのRuby 初めてのRuby](https://images-fe.ssl-images-amazon.com/images/I/51BI%2BoUtJCL._SL160_.jpg)
- 作者: Yugui
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/06/26
- メディア: 大型本
- 購入: 27人 クリック: 644回
- この商品を含むブログ (251件) を見る