default eye-catch image.

ブロック操作系まとめ

全然網羅できてないけどブロック操作系まとめ。 [arst_toc tag=\"h3\"] スコープを作ってコレクションを操作できるのはそうだとして、 ブロック内の評価値をまとめたものがブロックの評価結果となるところがポイント。 コードがぐっと短くなって気分が良い。 基本的なeach 最も基本的な配列、ハッシュのeach。配列、ハッシュをレシーバとしてeachメソッドを呼び出す。 評価結果はレシーバ自身。 arrays = [100, 200, 300] rets = arrays.each do |value| p value end # 100 # 200 # 300 # [100, 200, 300] p rets # [100, 200, 300] hashes = {a1:\"a1\", a2:\"a2\", a3:\"a3\"} rets = hashed.each do |value| p value end # [a1:\"a1\", a2:\"a2\", a3:\"a3\"] # {a1: \"a2\"} # {a2: \"a2\"} # {a3: \"a3\"} # [a1:\"a1\", a2:\"a2\", a3:\"a3\"} p rets # [a1:\"a1\", a2:\"a2\", a3:\"a3\"} each_with_index 配列の順序数を付けることができる。 arrays = [100, 200, 300] arrays.each_with_index do |value,index| p \"#{index}_#{value}\" end # \"0_100\" # \"1_200\" # \"2_300\" # [100, 200, 300] each_key, each_value ハッシュのキーのみ、値のみをブロックで使う場合は以下。 キー、値の両方を使える制限無しの状態でどちらかを使う、というのではなく、 初めからキー、値のどちらを使うかを宣言して、それだけを使うという拘りビリティ。 hashes = {a1:\"a1\", a2:\"a2\", a3:\"a3\"} rets = hashes.each_key do |key| p key end # :a1 # :a2 # :a3 # {:a1=>\"a1\", :a2=>\"a2\", :a3=>\"a3\"} rets2 = hashes.each_value do |value| p value end # \"a1\" # \"a2\" # \"a3\" # {:a1=>\"a1\", :a2=>\"a2\", :a3=>\"a3\"} upto, downto ループを回して、制御変数をインクリメント、デクリメントするケースには専用の構文を使う。 Rubyにはインクリメント演算子は無いし、腐ってもforの外で用意した変数に対して+1を自己代入したりしない。 何より、英語の構文と同じところが気持ちが良い。 100.upto(103) do |i| p i end # 100,101,102,103 103.downto(100) do |j| p j end # 103,102,101,100 times n回の構文,times。 3.times do |i| p i end # 0,1,2 map mapは、レシーバの各要素分繰り返す。ブロックの評価値は各要素に対応する値となり、新たな配列が返る。 eachだと、評価結果がレシーバ自身であるためレシーバを加工して返す用途に使えないが、 mapを使うと、ブロックの応答として加工済みの配列を返せるので、制御構文がグッと短くなって気持ちが良い。 あくまでもレシーバの個数繰り返すので、ブロックでnilを返すと、評価結果の該当要素がnilになる。 arrays = [1, 2, 3] rets = arrays.map do |i| \"values_#{i}\" end [\"values_1\", \"values_2\", \"values_3\"] rets2 = arrays.map do |i| \"values_#{i}\" if i <3 end ["values_1", "values_2", nil] ただ、順序数付きのmap_with_indexはこのような動きをしない。 arrays = [1, 2, 3] rets = arrays.map_with_index do |index,value| \"#{index}_#{value}\" end p rets # {評価結果なし} select 前述の通り、mapはレシーバの個数分繰り返すため、ブロック内の最終評価値がnilとなった場合、 評価値の該当要素がnilになる。 そうではなく、nilでない評価結果をまとめて返したい場合はselectを使う。 rets3 = arrays.select do |i| \"values_#{i}\" if i <3 end ["values_1", "values_2"] まだまだ全然網羅できてないけど、とりあえず終了。

default eye-catch image.

procとlambda

[arst_toc tag=\"h3\"] Procとcallメソッド 以下では、get_closureメソッドにより、クロージャオブジェクトを生成している。 その際初期値を設定している。 クロージャオブジェクトのcallメソッドによりクロージャを実行する。 初期値を設定した変数initial_valueはクロージャのスコープなので、 クロージャの外からは一切存在を管理する必要がない。 def get_closure initial_value Proc.new{|up| initial_value += up} end closure = get_closure(100) closure.call(10) # 110 closure.call(20) # 130 proc内でのreturn proc内でreturnすると、procの呼び出し元のスコープを抜ける。 procの呼び出し位置で処理が止まるため、そのあとの処理は実行されない。 以下callerというメソッド内でprocを実行するが、 procがreturnすることで、proc.callの実行後callerのスコープを抜ける。 なので2は評価されない。 この動きは後のlambdaと異なる。 def caller proc = Proc.new{ return 1 } proc.call 2 end Procオブジェクトをブロックに変換 作っておいたクロージャオブジェクトをメソッド実行時にブロックとして使用することができる。 メソッドの引数として、&を付与してProcオブジェクトを渡す。 def func hoge hoge + yield end closure = Proc.new {5} func(10, &closure) # 15 ブロックをProcオブジェクトに変換 ブロックをProcオブジェクトとして受けることができる。 def func2 hoge, &proc hoge + proc.call end func2(100) do 200 end # 300 lambda lambdaもprocを返すが、Proc.newとは異なる動きをする。 procの実行時にreturnするとprocの呼び出し元のスコープを抜けていた。 lambdaは実行時にreturnしてもlambdaの呼び出し元のスコープを抜けない。 下の例でlambdaが返したprocが途中で終わっても callerはそこで抜けず、proc.callの後が実行される。 def caller proc = lambda{ return 1 } proc.call 2 end lambdaの別の書き方 以下のように格好良く書ける。他の言語の同様の構文に似せた感じ。 lmd2 = ->(hoge,fuga) { hoge + fuga } lmd2.call(100,200) # 300

default eye-catch image.

ブロック(クロージャ)とスコープ

[arst_toc tag=\"h3\"] Ruby固有のスコープの扱いについて追記。 ブロックとスコープ メソッド呼び出しの直後にブロックを指定することができる。 例えば、以下においてメソッドfuncを呼び出す際に引数1と同時にdoから始まりendで終わるブロックを指定している。 ブロックの中ではx1という変数に2を代入していて、それがブロックの評価値となる。 ブロック付きで呼び出されたメソッドの中では、ブロックの評価値をyeildという特殊変数で受け取ることができる。 つまり、メソッドfuncの中では、引数y1=1と、ブロックの評価値2の和の評価が行われる。 def func y1 y1 + yield end # 3 func (1) do x1 = 2 end なお、ブロックはdo..endだけでなく、{..}でも書ける。 Rubyの掟的には、複数行のブロックはdo..end、1行のブロックは{..}とのこと。 func (1) { x1 = 2 } ちなみに、ブロックの中と外はスコープが異なる。 ブロックの中で確保した変数x1は、スコープの外からは見えない。 ブロックの中で確保した変数はブロックの評価が完了した時点で破棄される。 func (1) { x1 = 2 } p x1 # Exception 破棄されるのはブロックで初めて確保した変数であって、 ブロックの外部の変数をブロック内で使用した場合は、 ブロック内での操作がブロック外の変数に影響する。 例えば、以下のように予めブロックの外で変数x1を確保しておき、 ブロックにより加算するという状況で、ブロック内のx1は紛れもなくブロック外のx1。 x1はブロックにより束縛される(キリっ)。 ブロックの評価後に評価すると、確かにブロック内の加算が行われた後。 x1 = 10 func (1) { x1 += 2 } # 13 p x1 # 12 Rubyの特殊なスコープ事情 変数の束縛について追記。他の言語では動きそうな以下のコードはRubyでは動かない。 Rubyではオブジェクトやメソッドの壁を超えて変数を参照することはできない。 (Railsではインスタンス変数を使って超えちゃってるけど..) fuga = 20 def myfunc p fuga end ブロックを使うことで初めて実行時の環境(コンテキスト,文脈)を共有できる。 ここで一般化して良いのかわからないけども、 処理の生成時の変数を束縛するものをクロージャというらしい。 実行時の環境を動的に使えて便利だな、ぐらいの認識だったけど、 変数の束縛がポイント。 ブロックの引数 ブロック、つまりクロージャの引数の定義方法と使いかたは以下の通り。 クロージャ内の先頭で引数を|で囲む。かなり特殊に見える。慣れだろうか。 def func2 x2, y2 x2 + yield(y2,30) end p func2(10,20){|x,y| x+y} # 60 メソッド側でブロックが指定されたか調べる どんなケースでそんな使いかたをするのか.. メソッド側で呼び出し時にブロックが指定されてか否かを調べることができる。 def func3 x3,y3 return x2 + yield(y2,30) if block_given? 0 end p func3(10,20){|x,y| x+y} # 60 p func3(10,20) # 0

default eye-catch image.

範囲リテラル、case式、while式

[arst_toc tag=\"h3\"] 範囲を表すリテラルが言語仕様として準備されている。 範囲リテラル 範囲クラスはRangeクラスのインスタンス。 \"..\"により開始、終了の両方を含む範囲を表現する。\"...\"だおt終了は含まれない。 def func for var in 1..10 do p var end end func # 1 2 3 4 5 6 7 8 9 10 def func2 for var in 1...10 do p var end end func2 # 1 2 3 4 5 6 7 8 9 包含と同値 include?により範囲に値が含まれるかどうかを調べられる。 (1..5).include?(3) # true (1..5).include?(6) # false なお、===演算子も包含関係を表す。 (1..5) === 3 # true (1..5) === 10 # false ==演算子は同値関係を表す。 (1..5) == (1..5) # true (1..5) == 3 # true 添字演算子 配列の添字演算子に範囲を指定することができる。何番目から何番目という表現はかなり直感的。 a = [ 1, 2, 3 ,4 ,5] p a[1..2] # [2..3] p a[1,3] # 文字列の添字演算子にも範囲を指定することができる。部分文字列を範囲で表現できる。直感的。 a = \"abcdef\" p a[1..2] # bc case式 phpなど他の言語のswitch文。case when.. と書く様子。 でもなぜswitchではいけなかったのだろうか。 case式自体の評価値はcase式内で最後に評価された値となる。 def hoge a case a when 10 then p \"first\" when 20 then p \"second\" else p \"third\" end end hoge 10 # \"first\" hoge 20 # \"second\" hoge 30 # \"third\" whenで何が行なわれているかというと、===演算子によって同値の判断がされている。 なので、whenにRangeを指定すると、===演算子によって包含関係が評価される。 while式 phpのwhileと同等。条件が真である間繰り返す。 i = 0 while (0..5) === i do p i i += 1 end # 1 2 3 4 5 phpなどにもあるように、ループの末尾にwhileを書くことができる。 最初の1回は必ず実行される例のやつ。 後に置くので\"後置while\"という名前がついている。 i=0 begin p i i+=1 end while (1..4) === 1 # 0 1 2 3 4 後置whileとは別に、後に置くが\"修飾詞\"として使う書き方がある。 最初の1回はwhileが評価されるところが後置ifと異なる。 i=0 p i += 1 while (0..4) === i # 1 2 3 4 5 until式 条件が真になるまで繰り返す(真になったら抜ける)、専用の条件式。 Rubyは条件式を書く時に否定文を書く必要がない。(たぶん) i=0 until i===5 do p i i+=1 end # 0 1 2 3 4

default eye-catch image.

ハッシュリテラル

要素の順序性がある場合に使う配列と、順序性がない場合に使うハッシュ。 Rubyのハッシュの言語仕様について。 [arst_toc tag=\"h3\"] 基本的な書き方 PHPと同じようにキーとして文字列を使う場合は以下の通り。 a = {\"hoge1\" => 100, \"hgoe2\" => 200, \"hoge3\" => 300} a[\"hoge1\"] # 100 a[\"hoge2\"] # 200 a[\"hoge4\"] # nil キーとしてシンボルを使う場合は以下の通り。Rubyっぽくなる。 Ruby1.9以降はこちらを使う。 b = {:hoge1 => 100, :hoge2 => 200, :hoge3 => 300} b[:hoge1] # 100 b[:hoge2] # 200 b[:hoge4] # nil Hash.new()による生成 Hash.new()により配列の初期値として新たに確保した変数を設定できる。 Array.new()と同様に、全ての要素として同じオブジェクトを設定する。 a = Hash.new(100) a[:hoge1] # 100 a[:hoge1].object_id # 12345 a[:hoge2] # 100 a[:hoge2].object_id # 12345 []による生成 面倒くさいことに、キーと値が交互に現れる配列からハッシュを生成できる。 その書き方は以下の通り。 a = Hash[:hoge1, 100, :hoge2, 200, :hoge3, 300] # [:hoge1=>100,:hoge2=>200,:hoge3=>300] b = [[:hoge1,100],[:hoge2,200],[:hoge3,300]].to_h # [:hoge1=>100,:hoge2=>200,:hoge3=>300] 関数の引数、波カッコの省略 関数にハッシュを引数として与える場合、ハッシュを構成する波カッコを省略できる。 というか、引数の数が合わなかったときに末尾の処理の一つである様子。 ハッシュ引数の波カッコの種略を引数の先頭にもってくると(末尾の引数でないと)、例外が発生する。 def func a, b, c c end func 100,200,:hoge1=>300,:hoge2=>400 # {:hoge1=>300,:hoge2=>400} func :hoge1=>100,:hoge2=>200,300,400 func :hoge1=>100,:hoge2=>200,300,400 # 例外 キーワード引数 Rubyっぽい書き方。キーワード引数。 キーワードにシンボルで名前をつけることができる。関数を呼び出す時の可読性が向上する。 def func hoge1:, hoge2:, hoge3 hoge1 + hoge2 + hoge3 end func 100,200,300 # 600

default eye-catch image.

配列、配列演算、繰り返し

本日の素振り。 [arst_toc tag=\"h3\"] 配列 配列はArrayクラスのインスタンス。 a = Array.new(3) # [nil,nil,nil] b = Array.new(2,\"hoge\") # [\"hoge\",\"hoge\"] 配列は[]で表す。 a = [10,20,30] # [10,20,30] a[1] # 20 b = [20,true,\"hoge\"] # [10,true,\"hoge\"] b[2] # \"hoge\" b[3] # nil %記法で配列生成 配列の要素が文字列である場合に限って、%W、%wによって文字列を配列化できる。 デリミタは半角スペース、%Wでダブルクォート、%wでシングルクォート(なし)。 自動的にダブルクォート、シングルクォートで括るため、 文字列の配列を作るためにダブルクォート、シングルクォートで汚すことを防げる。 p = %W(hoge fuga) # [\"hoge\",\"fuga\"] q = %w(hoge fuga) # [\'hoge\',\'fuga\'] joinで配列結合 配列と配列を結合して新しい配列を作るのではなく、要素を文字列として結合する。 p = [100,200,300] # [100,200,300] p.join # \"100200300\" p.join(\"_\") # \"100_200_300\" 配列の生成 Array.new()を使うと同じオブジェクトを持つ配列を作れる。 要素分の変数が確保されるのではなく、指定した値を持つ変数が1つ確保されて並ぶ。 a = Array.new(2,\"hoge\") # [\"hoge\", \"hoge\"] a.object_id # 4032 b.object_id # 4032 a[0].replace(\'fuga\') # [\"fuga\", \"fuga\"] a.object_id # 4032 b.object_id # 4032 Array.new(){}だと要素数分の変数が確保されて並ぶ。 a = Array.new(2){\'hoge\'} # [\"hoge\", \"hoge\"] a[0].object_id # 4033 a[1].object_id # 4034 範囲外アクセス 配列の大きさを超えてアクセスしたとき、例外とならず、アクセスしたところまで配列が広がる。 最初の位置から作った最後の位置までnilで埋められる。 a = Array.new(3){\"hoge\"} # [\"hoge\",\"hoge\",\"hoge\"] a[5] = \"fuga\" # [\"hoge\",\"hoge\",\"hoge\",nil,nil,\"fuga\"] 負の添え字アクセス 何が何でもコード行を削減したい意思! 配列に負の添え字でアクセスすると\"末尾から数えた位置\"という意味になる。 a = [\"hoge1\", \"hoge2\", \"hoge3\"] # [\"hoge1\", \"hoge2\", \"hoge3\"] a[-1] # \"hoge3\" 配列のスライス phpのarray_slice()に相当するやつ。指定したインデックスから何個分というやつ。 a = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6] a[2,3] # [2, 3, 4] 以下のように指定したインデックスから何個分を置き換えられる。 a = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6] a[1,2] = \"hoge\" # [0, \"hoge\", 3, 4, 5, 6] b = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6] b[1,2] = \"hoge\", \"fuga\" # [0, \"hoge\",\"fuga\", 3, 4, 5, 6] c = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6] c[1,2] = \"hoge1\", \"hoge2\", \"hoge3\" # [0, \"hoge1\",\"hoge2\",\"hoge3\", 3, 4, 5, 6] 複数の戻り返却と多重代入 複数の値を返す関数を定義する。複数の値を返すように見えるが配列が返っている。 def test return \"hoge1\", \"hoge2\", \"hoge3\" end a, b, c = test # [\"hoge1\", \"hoge2\", \"hoge3\"] a # \"hoge1\" b # \"hoge2\" c $ \"hoge3\" 戻りとしてネストした配列を返すことができて、同じ構造の変数に代入できる。(多重代入) def test2 return [[\"hoge1\", \"hoge2\"], \"hoge3\"] end (x,y),z = test2 # [[\"hoge1\",\"hgoe2\"], \"hoge3\"] +、-演算子 左オペランドと右オペランドの要素の加算、左オペランドから右オペランドの減算 a = [\"hoge1\",\"hoge2\"] # [\"hoge1\",\"hoge2\"] b = [\"hoge2\",\"hoge3\"] # [\"hoge2\",\"hoge3\"] a + b # [\"hoge1\",\"hoge2\",\"hoge2\",\"hoge3\"] a - b # [\"hoge1\"] b - a # [\"hoge3\"] 減算の場合、左オペランドに重複があるときは全て削除される x = [\"hoge1\",\"hoge1\",\"hoge2\"] # [\"hoge1\",\"hoge2\",\"hoge3\"] y = [\"hoge1\"] x - y # [\"hoge2\",\"hoge3\"] *演算子 右オペランドが数値の場合は左オペランドをその回数繰り返す。 右オペランドが文字列の場合はjoinと同じ。 a = [1,2,3] a * 2 # [1,2,3,1,2,3] for式,each式 PHPのforeachに近いforとeach。forは期待と異なりループの中と外はスコープが同じ。 for内の変数をfor外でアクセスできる。 for value in [100,200,300] inner_loop = 500 end inner_loop + 100 # 600 対してeachはループ内とループ外でスコープが異なりeach内の変数はeach外で未初期化。 [100,200,300].each do inner_look2 = 500 end inner_loop # undefined variable

default eye-catch image.

symbol、参照、破壊的メソッド

[arst_toc tag=\"h3\"] シンボル 文字列そのものに意味はなく、単純にラベルとして文字列を扱いたいというときシンボルを使う。 シンボルのポイントは、文字の並びが同じであれば(同値であれば)同一であること。 hoge1 = :hoge1 p hoge1 # 524328 hoge2 = :hoge1 p hoge2 # 524328 hoge3 = :hoge3 p hoge3 # 324648 文字列からシンボルに変換できる。 hogeA = \"hoge1\".to_sym p hogeA.object_id # 524328 値の同値性と同一性 演算子==は、例えば2つの文字列の値が等しいかどうか(同値であるか)を比較する。 一方で、2つの変数のobject_idが等しいかどうか(同一であるか)を比較するために、 equal?メソッドを利用する。 hoge_x = \"hoge1\" hoge_y = \"hoge1\" p hoge_x == hoge_y # true p hoge_x.equal? hoge_y # false オブジェクトと参照 変数を宣言すると(つまりリテラルを指定すると)オブジェクトへの参照が与えられる。 以下の場合、\"hoge\"という一つのオブジェクトをhoge1、hoge2が参照する形になる。 hoge1 = \"hoge\" hoge2 = hoge1 hoge1.equal? hoge2 # true 片方の変数について値を変更した場合、その変更に対応するオブジェクトが新たに作られ、 新しいオブジェクトへの参照が作られる。 hoge1 = \"hoge\" hoge2 = hoge1 hoge2 = hoge2 + \"fuga\" p hoge1 # hoge p hoge2 # hogefuga hoge1.equal? hoge2 # false 実引数と仮引数の参照 関数に実引数として渡した変数と関数内で利用できる仮引数の参照は同じ。 ただし関数内で仮引数に対して処理すると、別の値が確保され、仮引数はその値への参照となる。 x = 100 x.object_id # 435123 def func x p x.object_id # 435123 x = 200 p x.object_id # 249821 end 破壊的メソッドと参照 変数の値を変更したときに参照を変えずに値を変更するメソッドを破壊的メソッドという。 慣例的に破壊的メソッドの末尾には「!」をつける。 破壊的メソッドと、代入時に別変数を確保して参照を変更するメソッドはしばしば同名で、 「!」により区別することがある。 残念ながら徹底されておらず、破壊的メソッドなのに「!」がなかったり逆もある。 w = \"hogehoge\" w.chop # \"hogehog\" w # \"hogehoge\" w.chop! # \"hogehog\" w # \"hogehog\"

default eye-catch image.

文字列、%記法

[arst_toc tag=\"h3\"] 文字列の式展開 PHPと同様にダブルクォート、シングルクォートにより文字列を表現する。 前者は変数展開あり、後者は変数展開なし。 実際には文字列内の\"式展開\"で、式のto_sメソッドの評価結果が文字列に展開される。 to_sメソッドを備えていれば独自クラスでも展開できる。 hoge = 10 p \"hoge is #{hoge}\" # hoge is 10 p \'hoge is #{hoge}\' # hoge is #{a} ただ文字列の中に変数を書いただけではダメで、変数展開用の識別子がいるんだな。 パーセント記法による式展開 シングルクォート、ダブルクォート以外を使って文字列を作ることもできる。 文字列の中でエスケープ無しでシングルクォート、ダブルクォートを使えて便利。 hoge = %*THIS IS TEST STRING \"HOGEHOGE\".*% もともとシングルクォート、ダブルクォートの区別により式展開するしないが決まっていたが、 当然パーセント記法を使うと式展開をそのままでは選べない。 パーセントの後にq、またはQを付与することで式展開をするしないを選ぶことができる。 なお、デフォルトは式展開をする。つまり%Qと同じ。 fuga = 100 %q*#{fuga + 100}* # \"#{fuga + 100}\" %Q*#{fuga + 100}* # \"200\" Rubyが複雑に見えるのはコイツのせいじゃないだろうか。 文字列の型変換 文字列から整数、浮動小数点、複素数、有理数などへ変換できる。 それぞれ、to_i、to_f、to_c、to_rというメソッドが用意されている。 厄介そうなことに、型変換ができない場合、変換できるところまで変換する。 そもそも先頭の文字が変換できないなら0。 \"100\".to_i # 100 \"10ab\".to_i # 10 \"1.1.1\".to_f # 1 \"hoge\".to_i # 0 デバッグ出力と関数 文字列をデバッグ用途に出力するときはpを使う。変数内の式は展開されない。 他に、print、putsで出力できる。こちらは変数内の式が展開される。 hoge = \"100 n\" p hoge # \"100 n\" puts 100 # 100 ヒアドキュメント 変数展開なしのヒアドキュメントは以下の通り。ヒアドキュメントの開始をシングルクォートにする。 ヒアドキュメントの終了は識別子も前にスペース禁止。 hoge = 100 str = <<'DOC' #{hoge} HOGE DOC 変数展開ありのヒアドキュメントは以下の通り。開始をダブルクォートにする。 hoge = 100 str = <<"DOC" #{hoge} HOGE DOC 文字列演算 文字列は+、*に対応している。 hoge = \"HOGE\" + \"FUGA\" # \"HOGEFUGA\" fuga = \"HOGE\" * 3 # \"HOGEHOGEHOGE\" <<により文字列連結。 hoge = \"HOGE\" hoge << "FUGA" # "HOGEFUGA" 比較演算 文字列の辞書順で比較する。 \"X\" \"Y\" # false \"XXX\" < "XXY" # true "XYZ" == "XYZ" # true 文字列長 .lengthメソッドにより文字列長を返す。バイト数ではなく文字数。 \"HOGEHOGE\".length # 8 sprintfと% %演算子にはsprintf相当の機能も備わっていて混乱する。 知らないと訳がわからない。 sprintf(\"THIS IS TEST INTEGER %02d\",1) # \"THIS IS TEST INTEGER 01\" p \"THIS IS TEST INTEGER %02d\" % 1 # THIS IS TEST INTEGER 01\"

default eye-catch image.

論理値、論理演算子、自己代入

真/偽 TrueClassのインスタンスがtrue、 FalseClassのインスタンスがfalse。 NilClassのインスタンスがnil。 true.class # TrueClass false.class # FalseClass falseとnilのみ偽として評価される。 falseとnil以外は全て真として評価。 この動きにより、変数に値が入っているかどうかは、 nilと比較する必要はなく変数を評価するだけで良い。 PHPのように変数に値が入っていることをチェックする必要はない。 if文 オーソドックスなif文。 compare = true if compare then \"OK\" end if文は式なのでif文を評価すると値が返る。 評価値はif式内で最後に評価された値となる。 a = if true 1 end p a # 1 後置ifという構文。簡単にコードが短くなって便利そう。だが...、 後置ifがfalseの場合でも、変数自体は確保される。が値が入らない。 意図せず変数がnilになるコードを書く可能性がある。 未定義の変数と、確保済みだが値なしの変数は明確に異なる。 a = 1 if true p a # 1 b = 1 if false p b # nil もし偽だったら、を書きたい場合はunless構文を使う。 unless false p 1 # 1 end 単項演算子?は使える。 n = (a==10) ? true : false 論理演算子 論理演算子は最後に評価したオペランドの値を返す。 評価結果(true,false)を返さない。 x = nil && 4 # nil y = 1 || 2 # 1 自己代入 変数が真でない場合に限りその変数に値を代入する自己代入。 これは、論理演算の際どい評価順序を利用していて、何故そうなるかは深い深い海の底にある。 z = z || 1 # 1 z ||= 1 # 1 zが真でない場合、つまりzがfalseかnilの場合に、 論理和演算子の右側のオペランドである1の評価結果(=1)がzに代入される。 未確保・未定義の変数の評価結果はnilなので、 未定義・未確保の場合に限り初期値を入れることができる。 z = 10 z = z || 1 # 10 &&とand、||とor、!とnot &&とand、||とor、!とnotという風に、同じ意味の論理演算子が対で用意されている。 それぞれ評価時の優先順位が異なる。(以下のようになる) p x && z # = p (x && z) p x and z # = (p x) and z

default eye-catch image.

整数リテラルとメソッド

[arst_toc tag=\"h3\"] 命名規則1.ローカル変数 変数名により用途が決まるので理解が必要。 資格系なら\"不適切な変数名\"を見抜けるかが大事。 ローカル変数は、代入が行われたブロックまたはメソッドの中だけで有効なスコープの変数。 ローカル変数は以下から構成される。ただし数字は先に来ない。 アンダースコア「_」 英数字 以下は変数名としてN.G. # アンダースコア以外の記号「-」が使われている variable-1 # これも safe? # 先頭が数値 100_or_1000 # 定数 VARIABLE 予約後を変数として再定義することはできない。 関数内ならスコープ外のローカル変数を参照すると例外。 kuma=20 def hoge(x,y) kuma end スコープ内で定義されているが評価されていない変数を参照するとnil。 def hoge(x,y) kuma = x + y if x > 10 kuma end > hoge 20,30 => 50 > hoge 5,10 => nil 命名規則2.グローバル変数 スコープに関係なくどこからでも参照できる変数。 構成する文字はローカル変数と同じ。ただし先頭は「$」。 アンダースコア「_」 英数字 $global = 100 def fuga(a,b) $global end > fuga 10,20 => 100 リテラルの種類 Rubyのリテラルは以下。 数値 論理値 文字列 シンボル 配列 ハッシュ 範囲 正規表現 ハッシュ 数値リテラル 整数と浮動小数点を使える。符号、指数表記、基数指定が可能。 基数指定でありえない値を指定すると例外。 +100 -200 2e2 # 2 に10の2乗を掛ける => 20 5e-e # 5 に10の-3乗を掛ける => 0.05 0b10 # 2進数の10 => 2 0o10 # 8進数の10 => 8 0d10 # 10進数の10 => 10 0x10 # 16進数の10 => 16 0xfg # 16進数でgはNG 数値リテラル内で桁表現ができる。(ロケールが違うときはどうなるのだろうか?) 100_000 => 100000 有理数(Rational)、複素数(Complex)もリテラル。 有理数は既約になる。浮動小数点にしないで保持できる。 また、小数を既約分数に変換できる!(すごい過剰な感じがする...) 25/45r # (5/9) 3.14r # (157/50) 複素数は実数、虚数の指定を整数、小数を使って表現できる。 12i # (0+12i) 5.6i # (5+6i) 有理数、虚数をミックスすることもできる。 3.14ri # (0+(157/50)i) 数値クラス 数値クラスのインスタンスである。 一言に数値クラスといっても継承関係によって詳細化されている。 a = 100 a.class # Fixnum a.class.superclass # Integer a.class.superclass.superclass # Numeric 数値クラスに実装された演算子により、数値演算、比較演算を実行できるようになっている。 数値演算 代表的な2項演算子は一通り使える。 1+1 # 2 1-2 # -1 3*3 # 9 4/2 # 2 4%3 # 1 代表的な比較演算子も一通り使える。 1==1 # true 1!=5 # true 1=1 # true 怪しい演算子が用意されている。UFO演算子。 演算子の左が大きければ1、等しければ0、右が大きければ-1。 500 10 # 1 500 500 # 0 10 500 # -1 と書いてあるけど、オペランドがNumericの時の話であって、 一般には「正」「0」「負」の振り分けと考えた方が良さそう。 オペランドが比較不能な場合はnilだそうだ。 if文を使って3方分岐するときに使える。 compare = (hoge fuga) if compare == 0 # hogeとfugaが比較可能で等しいとき elseif compare > 0 # hogeとfugaが比較可能でhogeが大きいとき else # 上記以外 (比較可能でfugaが大きいときを含む) end Rubyにはインクリメント演算子、デクリメント演算子は存在しない。 ので代わりに自己代入演算子を使う。 a = 100 a += 20 # 120 a -= 30 # 90 a *= 2 # 180 数値クラスの演算子であることを意識した書き方をすると、 数値の加算を以下のように書ける。 a = 100 a .+(50) # 150 メソッド 最後に評価された値が返る。returnで返すとそこで評価が終了する。 returnを書かないと関数内を最後まで読んで何が最終評価か理解しないといけないから 明示的returnを推奨する人もいるが、無いコードも多数ある。資格系はreturn無しの様子。 def add(x,y) x+y end > add 10,20 30=> nil def predict(hoge) if (hoge) then \"OK\" else \"NG\" end end > predict false => \"NG\" 仮引数のデフォルト値を指定できる。指定した引数の数が足りない場合は例外。 def add(x,y=200) x+y end add 10 => 210 キーワード引数 仮引数に名前をつけることができる。 これによりメソッド実行時に引数としてハッシュオブジェクトを渡せるようになる。 def add(x:,y:) x+y end add (x:100,y:200) => 300 キーワード引数にない引数名を指定すると例外。 def add(x:,y:) x+y end add (x:100,z:200) # 例外 ただし、キーワード引数を定義したメソッドに任意の引数を渡すことができる。 def add(x:,y:,**z) p z x+y end add (x:100,y:200,z:300) # {z=>300} => 300