No Programming, No Life

プログラミング関連の話題や雑記

Ruby基礎文法ひとめぐり

はじめに

やっぱり日本人ならRubyをやっとくべきかなと思いとりあえずひとめぐりしてみることにした。文法がGroovyに似ていることもありこれまで "わかったつもり" でいたのを払拭していきたいと思います。

表示

print が改行なし
puts が改行あり
p は主にデバッグ用

(*)

変数の種類と変数名

Rubyは先頭の1文字によって変数の種類が変わる。

foo #=> ローカル変数
@foo #=> インスタンス変数(@)
@@foo #=> クラス変数(@@)
$foo #=> グローバル変数($)
FOO #=> 定数(大文字から始まる)

(*)

数値にはアンダーバー区切りが使える

Rubyでは数値を表すときにアンダーバーが使える。これはよく3桁区切りで数値をカンマ区切りで表現するのに似せてある。
例えば、

print(3_420_500)

とすると

3420500

という出力を得る。
(* *)

インクリメント、デクリメント

Rubyには++がない。だから代わりに+=や-=を使うんだ。

例)
>> num = 1
=> 1
>> num += 1
=> 2
>> num -= 1
=> 1

(*)

文字列

Rubyの文字列はシングルクォートでもダブルクォートでもどちらもで使える。

>> str = 'abc'
=> "abc"
>> str = "abc"
=> "abc"

ダブルクォートを使うと、#{ } を使って式を展開した結果を文字列とすることができる。

>> list = ['abc', 'def', 'ghi']
=> ["abc", "def", "ghi"]
>> str2 = ">>> #{list.map{|s| s.capitalize}.join(',')} <<<"
=> ">>> Abc,Def,Ghi <<<"

(*)

RubyではGroovyと違って /文字列/ の形式はきっちり正規表現のクラスとして表現されているようだな。

>> 'abc'.class
=> String
>> "abc".class
=> String
>> /abc/.class
=> Regexp
<<

(*)

文字列操作

文字列操作色々。

結合
>> str1 = "aaa" + "bbb"
=> "aaabbb"
>> str2 = ["aaa", "bbb", "ccc"].join("-")
=> "aaa-bbb-ccc"
分割
>> record = "aaa,bbb,ccc".split(/,/) # Regexp型
=> ["aaa", "bbb", "ccc"]
>> record = "aaa,bbb,ccc".split(",") # splitは引数が文字列でもOKみたい
=> ["aaa", "bbb", "ccc"]
長さ
>> "abc".length
=> 3
>> "abc".size
=> 3

lengthでもsizeでもどちらでもOK。ここらへんはGroovyと同じですね。

切り出し
>> "abcd"[0, 2]
=> "ab"
検索
>> "abcd".index(/bc/)
=> 1
書き換え
>> str = "abcd"
=> "abcd"
>> str[2] = "!"
=> "!"
>> str
=> "ab!d"

(*)

配列

宣言

Rubyの配列は [ ] を使って宣言する。

>> ary1 = [100, 200, 300]
=> [100, 200, 300]
>> ary1[0]
=> 100
>> ary1[2]
=> 300

型が違ってもOK

>> ary = [100, "aaa", {"key" => "value"}]
=> [100, "aaa", {"key"=>"value"}]
長さ

配列の長さもlength, sizeどちらでもいいようだ。

>> ary = [100, "aaa", {"key" => "value"}]
=> [100, "aaa", {"key"=>"value"}]
>> ary.length
=> 3
>> ary.size
=> 3

配列操作あれこれ

先頭を取り出す
>> ary.shift
=> 100
>> ary
=> ["aaa", {"key"=>"value"}] # 元の要素に破壊的に働く
先頭に要素の追加はunshift
>> ary.unshift(5)
=> [5, "aaa", {"key"=>"value"}]
末尾要素を取り出す
>> ary.pop
=> {"key"=>"value"}
>> ary
=> [5, "aaa"] # 元の要素に破壊的に働く
末尾に要素を追加
>> ary.push(9)
=> [5, "aaa", 9]
まとめると

shift/unshiftは先頭要素に対して追加したり取り出し&削除したり。
pop/pushは末尾要素に対して追加したり取り出し&削除したり。

(* * *)

ハッシュ

ハッシュ操作あれこれ。

宣言

ハッシュは { } で囲み、キー => 値 の形でキーバリューを書き、カンマで区切る。

>> hash = {"a" => 1, "b" => 2, "c" => 3}
=> {"a"=>1, "b"=>2, "c"=>3}

キーはシンボルを使うのが一般的なんだって。
シンボルってのは :a みたいに コロン+英字ってなってるやつ。

>> hash2 = {:a => 1, :b => 2, :c => 3}
=> {:b=>2, :a=>1, :c=>3}
値の取り出し
>> hash["a"]
=> 1
>> hash2[:a]
=> 1
Groovyみたく、「.キー名」では取り出せない。
>> hash.a
NoMethodError: undefined method `a' for {"a"=>1, "b"=>2, "c"=>3}:Hash
from (irb):153
from :0
値の代入
>> hash["d"] = 4
=> 4
>> hash2[:d] = 4
=> 4
>> hash
=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
>> hash2
=> {:d=>4, :b=>2, :a=>1, :c=>3}
キー一覧
>> hash
=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
>> hash2
=> {:d=>4, :b=>2, :a=>1, :c=>3}
>|ruby|
>> hash.keys
=> ["a", "b", "c", "d"]
値一覧
>> hash.values
=> [1, 2, 3, 4]
キーの存在チェック
>> hash.key?("a")
=> true
>> hash.key?("e")
=> false
キーバリューペアの削除
>> hash.delete("d")
=> 4 #消す前のsizeが返って来るようだ
>> hash
=> {"a"=>1, "b"=>2, "c"=>3}

>> hash2.delete(:e)
=> nil #キーがないとnilが返って来るようだ
>> hash2
=> {:d=>4, :b=>2, :a=>1, :c=>3}

(* *)

ループ

ループいろいろ。

Array#eachでループ
Array#each
>> [1, 2, 3].each { |i|
?> puts i
>> }
1
2
3
=> [1, 2, 3]

※ each do |i| ... end でもOK

Integer#timesでループ
>> 5.times do |i| puts i end
0
1
2
3
4
=> 5
Kernel#loopでループ
loop { puts "stop me!" }

※無限に出力し続けるのでCtrl - c で止める。
(*)

集合操作

Enumerableに定義されている集合操作をいくつか試してみる。

条件に合致するものを選択する(select)
>> [1, 2, 3, 4, 5].select{|x| x.even?}
=> [2, 4]
条件に合致するものを除外する(reject)
>> [1, 2, 3, 4, 5].reject{|x| x.even?}
=> [1, 3, 5]
条件に合致する最初のものを返す(detect)
>> [1, 2, 3, 4, 5].detect{|x| x.even?}
=> 2

クロージャ (2011-04-11追記)

Rubyでクロージャを使いたい場合はlambdaを使えばいいみたい。

irb(main):012:0> clos = lambda do |x| #  二乗するクロージャを宣言
irb(main):013:1* x * x
irb(main):014:1> end
=> #<Proc:0x000001009822f8@(irb):12 (lambda)>
irb(main):015:0> clos(10) #呼び出しは.callとする必要があるみたい…
NoMethodError: undefined method `clos' for main:Object
	from (irb):15
	from /opt/local/bin/irb1.9:12:in `<main>'
irb(main):016:0> puts clos(10)
NoMethodError: undefined method `clos' for main:Object
	from (irb):16
	from /opt/local/bin/irb1.9:12:in `<main>'
irb(main):017:0> puts clos.call(10) #できた
100
=> nil
irb(main):018:0> puts clos.call(100) #できた
10000
=> nil

参考: Rubyの「クロージャ」再考 - バリケンのRuby日記 - Rubyist
v1.9系からはlambdaの宣言に新しい記法が追加されたとのこと。

irb(main):006:0> clos = ->(x, y) { x + y }
=> #<Proc:0x00000100934e90@(irb):6 (lambda)>
irb(main):007:0> puts clos.call(10, 20)
30
=> nil
  • >と(x,y)の間にスペースが入ってるとダメでした。

参考: ハチドリ本 6章 メソッド、proc、lambda、クロージャ - seven the programmer

まとめ

こうして見てると如何にGroovyがRubyから文法をパクってる取り込んでいるかがよくわかるな。
(*)