第3回 RUBY輪講
堀田美香
第3章 データ型とオブジェク
ト
1.配列
2.ハッシュ
3.ハッシュリテラル
4.ハッシュ値、等値性、ミュータブルな
 キー
5.範囲
6.シンボル
7. true、false、nil
8~19.オブジェクト
1.配列
   値の列で、添字によって値にアクセスできるよ
    うになっているもの
   配列の要素は全て同じクラスである必要はなく、
    任意のタイミングで変更できる
   配列のサイズは要素を追加すると、必要に応じ
    て伸びる
   配列の末尾よりも後ろの要素に値を代入すると、
    間にnil要素を挟んで自動的に拡張される。しか
    し、先頭よりも手前の要素に値を代入しようと
    するとエラーになる
配列リテラルは、全体が角かっこで囲まれ、カンマ
で区切られた値のリストである
[1,2,3]             #3個のFixnumオブジェクトを保持す
る配列
[-10…0,0…10, ]      #2個の範囲から構成される配列。
                    #末尾のカンマは許される
[[1,2],[3,4],[5]]   #ネストされた配列の配列
[x+y,x-y,x*y]       #配列要素としては任意の式が使える
[]                  #空配列のサイズは0

・ %w、%Wは配列リテラルを意味する
・ セパレータの中では、配列要素の文字列を囲む引用
符は不要であり、要素の間にカンマを入れる必要もない
・ 配列要素はカンマで区切られる
words = %w[this is a test]   #[„this‟, „is‟, „a‟,
・配列をArray.newコンストラクタで作成すると、プ
ログラムで生成した値を使って個々の要素を初期化
出来る

empty = Array.new   #[ ] : 新しい空配列

nils = Array.new(3)
            #[nil, nil, nil] : 3個のnil要素を持つ新しい
配列
zeros = Array.new(4,0)
            #[0, 0, 0, 0] : 4個の0要素を持つ新しい配
列
copy = Array.new(nils)
            #既存の配列の新しいコピーを作る
count = Array.new(3) {|i| i+1}
・配列要素の値は、角かっこの中に単一の整数(添字)
を入れたものを使って取得する
a = [0, 1, 4, 9, 16] #添字の自乗を格納する配列
a[0]          #先頭の要素は0
a[-1]         #末尾の要素は16
a[8]          #末尾を越えて読もうとするとnilが返され
る
a[-8]         #先頭より手前を読もうとしてもnilが返さ
れる

・上記の式は代入の左辺としても使うことができる
a[0] = “zero”   #aは[“zero”, 1, 4, 9, 16]
a[-1] = 1..16        #aは[“zero”, 1, 4, 9, 1..16]
a[-10] = 100         #エラー。
                #配列の先頭よりも手前の要素に代入
・先頭インデックスと要素数を表す2個の整数やRange
オブジェクトを添字とすることもできる
a = („a‟..‟e‟).to_a #Rangeが[„a‟, „b‟, „c‟, „d‟, „e‟]に変換され
るa[1,1]                  #[„b‟] : 要素が1個の配列
a[-2,2]                  #[„d‟, „e‟] : 末尾の2個の要素
a[0..2]                  #[„a‟, „b‟, „c‟] : 先頭の3個の要素

・これらの式を代入の左辺として使うと、部分配列を
右辺の配列の要素に置き換えることができる。
・この基本操作は、挿入や削除にも使える

a[0,2] = [„A‟, „B‟]      #aは[„A‟, „B‟, „c‟, „d‟, „e‟]になる
a[2…5] = [„C‟, „D‟, „E‟] #aは[„A‟, „B‟, „C‟, „D‟, „E‟]になる
a[0,0] = [1,2,3]         #aの先頭に要素を挿入する
a[-1,1] = [„Z‟]     #末尾の要素を別の要素に書き換える
・+を使えば、2つの配列を結合できる
a = [1, 2, 3] + [4, 5] #[1, 2, 3, 4, 5]
a = a + [ [6, 7, 8] ]         #[1, 2, 3, 4, 5, [6, 7, 8] ]
a = a + 9 #エラー。右辺は配列でなければならない

・+演算子は、両辺の要素を含む新しい配列を作成す
る
・既存の配列の末尾に新しい要素を追加したい場合は
<<を使う
・複数の要素を末尾に追加したい場合はconcatを使う

a=[]         #空配列からスタートする
a << 1          #aは[1]になる
a << 2 << 3     #aは[1, 2, 3]になる
a << [4, 5, 6]  #aは[1, 2, 3, [4, 5, 6] ]になる
・-演算子は、片方の配列からもう片方の配列を減算す
る
・右辺の要素は、配列内のどの位置にあっても構わない
[„a‟, „b‟, „c‟, „b‟, „a‟] – [„b‟, „c‟, „d‟]        #[„a‟, ‟a‟]
・Stringクラスと同様に、Arrayでも乗算演算子を使うと、
反復の意味になる
a = [0] * 8            #[0, 0, 0, 0, 0, 0, 0, 0]
・|は引数を連結し、重複する要素を全て取り除く
・&は両方の引数配列に含まれている要素を集め、重複
を取り除いた配列を返す
a = [1, 1, 2, 2, 3, 3, 4] ;          b = [5, 5, 4, 4, 3, 3,
2]
a|b           #[1, 2, 3, 4, 5] : 重複が取り除かれている
b|a           #[5, 4, 3, 2, 1] : 要素は同じだが、順序は逆
a&b           #[2, 3, 4]
Arrayクラスの役立つメソッド

・配列の要素を逐次的に処理するために使われる
eachイテレータ

a = („A‟..‟Z‟).to_a   #英字の配列を作る
a.each {|x| print x}
                  #1度に1字ずつアルファベットを出
力する

・調べておくと役に立つArrayメソッド
clear, compact!, delete_if, each_index, empty?, fill,
flatten!, include?, index, join, pop, push, reverse,
reverse_each, rindex, shift, sort, sort!, uniq!,
unshift
2.ハッシュ
   キーと呼ばれるオブジェクトの集合を保持し、
    個々のキーに値を対応付けているデータ構造

   キーを値にマッピングするので、マップとも
    呼ばれる

   個々のキーから値を連想するように導き出す
    ので、連想配列と呼ばれることもある
・このハッシュは、数字の名前を数字自体にマッピン
グする

numbers = Hash.new
#新しい空のハッシュオブジェクトを作成する
numbers[“one”] = 1
# ”one”というStringを1というFixnumにマッピングする
numbers[“two”] = 2
#ここで配列の記法を使っているということに注目
numbers[“three”] = 3
sum = numbers[“one”] + numbers[“two”]
#このようにして値を取得する
3.ハッシュリテラル

・全体が中かっこで囲まれ、カンマで区切られた
キー/値の対という形で記述

・キーと値は、= > という2文字の「矢印」で区切
られる

numbers = {“one” => 1, “two” => 2, “three” =>
3}
・ハッシュキーとして文字列よりもSymbolオブジェク
トの方が効率的に使える
numbers = { :one => 1, :two => 2, :three => 3 }
・Symbolとは、intentされたイミュータブルな文字列
で、プレフィックスとしてコロンが付けられた識別子
という形で記述される
numbers = { :one => 1, :two => 2, }
                      #余分なカンマは無視される
・Ruby1.9は、キーがシンボルのときには、コロンを
ハッシュキーの末尾に移動すると矢印を省略できる
numbers = { one: 1, two: 2,three: 3 }
・ただし、ハッシュキー識別子とコロンの間にスペー
スを入れてはならない
4.ハッシュ値、等値性、ミュータブル
なキー
・Rubyのハッシュはハッシュテーブルと呼ばれる
データ構造を使って実装されている
・ハッシュのキーとして使えるオブジェクトは、
キーのハッシュ値となるFixnumを返すhashという
名前のメソッドを持つ必要がある
・2つのキーが等しければ、このメソッドは同じ
ハッシュ値を返さなければならない
・キーが等しくない場合でも、同じハッシュ値にな
る場合はあるが、ハッシュテーブルの効率を上げる
には、重複するハッシュ値が尐ない方がいい
・hashクラスは、eql?メソッドを使ってキーが等
しいかどうかを比較する
・ほとんどのRubyクラスでは、eql?は==演算子と
同じように動作する
・eql?メソッドをオーバーライドする新しいクラ
スを定義するときには、hashメソッドもオーバー
ライドしなければ、そのインスタンスはハッシュ
のキーとして使えなくなってしまう
・クラスを定義してeql?をオーバーライドしない
場合、そのクラスのインスタンスはハッシュキー
として使われたときに、オブジェクトIDで比較さ
れる
・ハッシュキーとしてミュータブルなオブジェク
トを使うと問題が起きる

・オブジェクトの内容を書き換えると、一般に
ハッシュ値も変わる

・オブジェクトをキーとして使った後でそのオブ
ジェクトの内容を変更すると、内部ハッシュテー
ブルが壊れ、ハッシュが正しく機能しなくなる

・文字列はミュータブルだが、ハッシュキーとし
て良く使われるので、Rubyは文字列だけを特殊条
件として扱い、キーとして使われている文字列に
ついては、プライベートコピーを作っている
5.範囲

・Rangeオブジェクトとは、先頭の値から末尾の値
までの全ての値を表す
・範囲リテラルは、先頭の値と末尾の値の間に2個
または3個のドットを入れて記述する
・ドットが2個・・・末尾の値も含む(包含的)
・ドットが3個・・・末尾の値は含まない(排他的)
1..10    #1以上10以下の整数
1.0…10.0 #1.0以上10.0未満の数値
・値が範囲に含まれているかは、include?メソッド
でテストする
cold_war = 1945..1989
cold_war.include? birthdate.year
範囲の目的
・比較・・・ある値が範囲に含まれるかどうかを
判定する

・反復処理・・・範囲の端点のクラスがsuccメ
ソッド(後者関係を意味する)を定義する場合、範囲
のメンバは離散集合になっており、each、step、
Enumerableメソッドで反復処理できる

r = „a‟ .. ‟c‟
r.each{|1| print “[#{1}]”}          # ”[a][b][c]”と出力
r.step(2) { |1| print “[#{1}]”} # “[a][c]”と出力
r.to_a             # => [„a‟, „b‟, „c‟] : to_aはEnumerableメ
ソッド
・Stringクラスがsuccメソッドを定義しており、反
復処理できる範囲を離散範囲、端点がsuccメソッ
ドを定義していない範囲は反復処理できないので
連続範囲と呼ぶ

・端点が整数になっている範囲は離散範囲だが、
浮動小数点になっている範囲は連続範囲になる

・範囲リテラルから直接メソッドを呼び出したい
場合には、リテラルをかっこで囲まなければなら
ない

1..3.to_a # 3という数値からto_aを呼び出そうと
する
(1..3).to_a # => [1, 2, 3]
5.範囲のメンバかどうかのテ
スト
・Rangeクラスは、任意の値が範囲に含まれてい
るかどうか(範囲のメンバかどうか)をテストする
ためのメソッドを定義している
・範囲のメンバであるということの定義は2種類
ある
連続範囲のメンバテスト
・値xが次の式を満たす場合、xはbegin..endという
範囲のメンバである
begin <= x <= end
・値xが次の式を満たす場合、xはbegin…endという
範囲のメンバである
begin <= x < end

離散範囲のメンバテスト
・succを必要とする
・Range begin..endをbeing、being.succ、
being.succ.succを含む集合として扱う
・範囲のメンバであるなら集合のメンバであり、xと
いう値は、いずれかのsucc呼び出しの戻り値になっ
ているときに限り、範囲に含まれている
・離散範囲メンバテストは連続範囲メンバテスト
と比べてコストがずっと高くなる可能性がある

triplse = “AAA” .. “ZZZ”
triples.include? “ABC”         #true; 低速
triples.include? “ABCD”        #false
triples.cover? “ABCD”          #true; 高速
triples.to_a.include? “ABCD”   #false; 低速
6.シンボル

・Rubyの一般的な実装は、実装が把握しているす
べてのクラス、メソッド、変数の名前を格納する
シンボルテーブル(記号表)を管理している

・メソッド名はこのシンボルテーブル内でのメ
ソッド名の位置によって参照する

・・メソッド名はこのシンボルテーブル内でのメ
ソッド名の位置によって参照する
・シンボルリテラルはコロンをプレフィックスとす
る識別子や文字列という形で書ける

: symbol            #Symbolのリテラル
: “symbol”                 #まったく同じリテラ
ル
: „another long symbol‟
#スペースが含まれたシンボルではクォートが役に
立つ
s = “string”
sym = : “#{s}”      # : stringというSymbol

・シンボルは%sというリテラル構文を持っている

%s[“]        # : „ “ „と同じ
・シンボルはリフレクションコードでメソッド名を
参照するために良く使われる
・オブジェクトがeachメソッドを持つかどうかを知
りたければ、次のコードを使う

o.respond_to? : each

・オブジェクトが指定されたメソッドを持つかどう
かをテストし、持つようならメソッドを呼び出す

name = : size
if o.respond_to? Name
       o.send(name)
end
・internまたはto_symメソッドを使うと、Stringを
Symbolに変換できる
・to_sメソッドか、id2nameメソッドを使えば、逆
にSymbolをStringに変換できる

str = “string”      #文字列からスタート
sym = str.intern    #シンボルに変換
sym = str.to_sym       #同じことを行う別の
方法
str = sym.to_s      #再び文字列に変換
str = sym.id2name   #同じことを行う別の方法
7.True, false, nil
・trueとfalse・・・真と偽
・nil・・・値が無いことを示す
・これらのキーワードを評価すると、専用オブジェ
クトになる
true → TrueClass
false → FalseClass
nil → NilClass
・RubyにはBooleanクラスが無い
・変数がnilかどうかをチェックする方法
o == nil  #oはnilか?単純に比較
o.nil?        #nil?メソッドを使う
8.オブジェクト
・Rubyはオブジェクト指向言語として非常に純度
が高い

・全ての値はオブジェクトであり、Objectという
名前のクラスを継承している


・これより、Rubyの全てのオブジェクトが共通に
持つ機能、特徴を説明する
9.オブジェクト参照
・Rubyはオブジェクト指向言語として非常に純度
が高い

・全ての値はオブジェクトであり、Objectという
名前のクラスを継承している


・これより、Rubyの全てのオブジェクトが共通に
持つ機能、特徴を説明する
・Rubyでオブジェクトを操作する時、プログラムが操
作しているのはオブジェクト自体ではなく、オブジェ
クトの参照である
・変数に値を代入するときには、変数にオブジェクト
の参照を格納しているだけである
s = “Ruby”    #Stringオブジェクトを作り、参照を s に格納する
t=s           #参照のコピーを作って t に格納する。
              # s と t は同じオブジェクトを参照する
t[-1] = “ ”   # t に格納された参照を介してオブジェクトを書き換
える
print s       # s を介して書き換えられたオブジェクトにアクセス
する。
              #”Rub”と表示
t = “Java”    # t は別のオブジェクトを参照している
print s,t           #”RubJava”と表示
10.オブジェクトの寿命
・リテラル構文を持っていないクラスのオブジェク
トは明示的に作成しなければならない
myClass.new

・Rubyは不要になったオブジェクトを自動的に開
放するガベージコレクションと呼ばれるテクニック
を使っている

・オブジェクトやメモリの明示的な開放を必要とす
る言語のプログラムと比べて、メモリリークを起こ
しにくい
11.オブジェクト識別子
・すべてのオブジェクトは、Fixnumのオブジェク
ト識別子を持っており、この値はobject_idメソッド
によって取得できる

・この値はオブジェクトの生涯に渡って一定で一意
的

・__id__はobject_idと同じ意味を持つが非常用であ
る

・objectクラスは単純にオブジェクトのIDを返す
hashメソッドを実装している
12.オブジェクトのクラスと
 型
・Rubyでは、オブジェクトのクラスが何かを取得す
るための方法が複数ある
①オブジェクト自体にたずねる
o = “test”      #これは値
o.class            #Stringクラスを表すオブジェクト
を返す

②オブジェクトの階層を知りたい場合
o.class                   #String: oはStringオブジェクト
o.class.superclass #Object: Stringのスーパークラスは
Object
o.class.superclass.superclass
                   #nil: Objectはスーパークラスを持たない
③クラスをチェック(直接比較)
o.class == String   #oがStringならtrue
・instance_of?メソッドでも同じことをする
o.instance_of? String    #oがStringならtrue
④オブジェクトがそのクラスのサブクラスのインスタ
ンスかどうか
x=1                 #この値で操作する
x.instance_of? Fixnum     #true: Fixnumのインスタンス
x.instance_of? Numeric    #false: x.instance_of? では継承関係が
分からない
x.is_a? Fixnum            #true: xはFixnum
x.is_a? Integer           #true: xはInteger
x.is_a? Numeric           #true: xはNumeric
x.is_a? Comparable #true: ミックスインモジュールにも対応
x.is_a? Object            #xがどのような値でもtrue
13.オブジェクトの等値性

・Rubyにはオブジェクトが等しいかどうかを比較する
方法が沢山ある

①equal?メソッド
・2つの値が同一のオブジェクトを参照しているかどうか

a = “Ruby” #1個のStringオブジェクトに対する1個の参照
b = c =“Ruby”#別のStringオブジェクトに対する2個の参照
a.equal?(b) #false: aとbは異なるオブジェクトを参照してい
る
b.equal?(c) #true: bとcは同じオブジェクトを参照している
②==演算子
・等しいかどうかをテストするために最もよく使われ
る方法
・Objectクラスではequal?クラスと同じ意味に過ぎな
い

a = “Ruby” #1個のStringオブジェクト
b = “Ruby” #内容は同じだが別のStringオブジェクト
a.equal?(b) #false: aとbは同一のオブジェクトではない
a == b #true: しかし、2つの異なるオブジェクトは同じ値を持って
いる

③eql?メソッド
・eqlual?の同義語
・型変換をしない厳格な==として使うことが多い
1 == 1.0   #true: FixnumとFloatは==になることがある
④===演算子
・通称「case等値」
・case文のターゲット値がその文のwhen節に一致する
かどうかのテストに使われる
・両辺が同じシンボルになっているか、同じ文字の並
びを格納する文字列になっていれば、trueを返す
(1..10) === 5    #true: 5は1..10の範囲内
String === “s”   #true: “s”はStrungクラスのインスタンス
:s === “s”       #Ruby 1.9ではtrue

・このように明示的に使われることはあまりない
・case文の中で暗黙のうちに使われる
14.オブジェクトの順序

・クラスは< = >演算子を実装して順序を定義する
1<=>5         # -1: 左辺が右辺よりも小さい
5<=>5         # 0: 両辺が等しい
9<=>5         # 1: 左辺が右辺より大きい
“1” < = > 5   # nil: 整数と文字列は比較できない

・< = >演算子がnilを返した場合、比較演算子はfalseを
返す(Floatの特殊値NaNなど)
nan = 0.0/0.0#0割る0は数値ではない(not a number)
nan < 0      #false: 0より小さくない
nan > 0      #false: 0より大きくない
nan == 0     #false: 0と等しくない
nan == nan #false: 自分自身とさえ等しくない
15.オブジェクトの変換

明示的な変換
to_s   #Stringへの変換
to_i   #Integer
to_f   #Float
to_a   #Array
to_c   #Complex
to_r   #Rational
暗黙の変換
to_int    #整数に近くなりたいオブジェクトのためのメ
ソッド
to_str    #文字列に近くなりたい
to_ary       #配列に近くなりたい
to_hash   #ハッシュに近くなりたい

・実装されているものはあまりない

変換関数
・kernelモジュールは、グローバルな変換関数として動
作する4種類の変換メソッドを定義している
Array, Float, Integer, String
・Integer関数は、引数をFixnumかBignumに変換する
・末尾に数字以外の文字が含まれているものは認めな
い
算術演算子の強制型変換
・数値型はcoerceという名前の変換メソッドを定義し
ている
・coerceメソッドは必ず同じ型の2つの数値を格納す
る配列を返す
1.1.coerce(1)             #[1.0,1.1]: FixnumからFloatに強制
変換
require “rational” #Rationalを使う
r = Rational(1,3) #Rational型の1/3
r.coerce(2) #[Rational(2,1),Rational(1,2)]: Fixnumから
Rationalに

論理値の型変換
・Rubyの論理演算子や、論理式を使う条件分岐、繰り
返し構文はtrueやfalse以外の値とも併用できる
16.オブジェクトのコピー

・cloneとdupは、呼び出し元オブジェクトの浅いコ
ピーを返す

clone
・オブジェクトのフリーズ、汚染状態をともにコピー
する
・特異メソッドをコピーする

dup
・汚染状態しかコピーしない
・特異メソッドをコピーしない
17.オブジェクトの永続化

・オブジェクトの状態は、クラスメソッドの
Marshal.dumpにオブジェクトを渡せば保存できる

・オブジェクトに復元するには、そのデータを含む文
字列かI/OストリームをMarshal.loadに渡す

・オブジェクトの永続化するのは、オブジェクトの状
態を保存して後で利用するための非常に簡単な方法で
ある
18.オブジェクトのフリーズ

・freezeメソッドを呼び出せばフリーズすることがで
きる
・フリーズされたオブジェクトはいミュータブルにな
る

・フリーズされているかどうかは、fronzn?メソッドで
チェックできる

・フリーズされたオブジェクトを「解凍」することは
できない
19.オブジェクトの汚染状態

・セキュリティ上のリスクを回避するために信頼でき
ないユーザー入力からつくられたデータを追跡するた
めに提供されるソリューション

・taintメソッドを呼び出すと、オブジェクトに汚染さ
れているというマークを付けることができる

・ユーザー入力(コマンドラインオプション、環境変
数など)は自動的に汚染済みマークを付けられる

・untaintメソッドで元の状態に戻すことができる
(よく解析してセキュリティリスクが無いことを確認した場合だけにしなければ
ならない)

第3回輪講