Ruby社内勉強会 第2回


概要

単なる社内勉強会の記録ですが、Ruby初学者の参考になるかもしれないので内容を公開します。
今回は2回目です。

背景、進め方など

注意事項

  • サンプルコードについては基本的に教材サイトを参照のこと
  • 見出しは教材サイトの見出しと一致させている。一部わかりにくい見出しもあるが、それもそのまま教材サイトと合わせている

学んだ内容

教材サイトで学んだ範囲

「3. 便利なオブジェクト」の「ハッシュ」から「7. クラスとモジュール1」の「アクセスメソッド」まで

詳細

3. 便利なオブジェクト

ハッシュ

  • いわゆる連想配列
  • JavaでいうならLinkedHashMapに相当する
    • 要素を追加した順番を保持している(古いバージョンのRubyでは保持していなかった)
  • {}を使ってハッシュオブジェクトを生成できる
  • 配列と同じような記法で要素の参照、追加、更新ができる
  • 削除はdeleteメソッド(単体削除)やclearメソッド(全削除)で行う
  • ハッシュと直接は関係ないが、シンボルという型がある
    • ハッシュのキーとしてよく使う
  • ハッシュの値にはどんな値でも入れられる。ハッシュの入れ子もできる

4.条件判断

unless

  • if文の逆で条件式が偽の場合に実行される
  • 安易に使うとわかりにくくなるかも?

!演算子

  • 真偽を反転させる
  • Javaの!演算子と同じ使い方ができる
  • 同じ機能を持つものとしてnotがある

修飾子

  • いわゆる後置if
  • 文の後ろにifやunlessの条件分岐を書ける
  • 一行で書きたいときなどに使う

case

  • Javaのswitch文に近い
  • breakは書かないので、breakの記述漏れで全部実行されてしまうといったバグの心配はない

真偽値

  • Javaと特に変わらないのでスキップ

比較演算子

  • 数値の大小比較ができる
  • 動作的にはJavaと特に変わらない

論理演算子

  • ||(論理和)と&&(論理積)は動作的にはJavaと変わらない
    • ショートサーキットである点も同じ
  • 論理和はand、論理積はorも使える

5. 繰り返し

until

  • while文の逆で、条件式が偽である間、処理を繰り返す
  • 範囲はdo endで囲うがdoは省略可能
  • 安易に使うとわかりにくくなるかも?
  • 余談だが、Rubyにdo while文はなさそう

ブロック付きメソッド呼出し

  • 前回もやったが、配列などに対してeachメソッドを使える
    • ブロックで渡した処理を要素数分繰り返す
    • ハッシュに対しても使える。ブロックパラメータを2つ書くとキー、値のそれぞれを代入してくれる
    • 先述の通り、ハッシュは追加された順番を保持するため順番通りにイテレートできる
      • 教材サイトの例で順番通りになっていないのは、古いバージョンベースの説明だから
    • Rubyでは繰り返しの記述ではこのeachがよく使われる
  • これも前回触れたが整数値に対してtimesメソッドを使える
    • 数値の回数分繰り返す
    • 余談だが教材サイトのサンプルコードの通り、ブロックは{}で囲うこともできる
  • for文はJavaの拡張for文に相当する
    • あまり使われない
  • 無限ループさせたい場合はloopメソッドを使う

繰り返しの制御

  • breakはJavaと同じ
  • nextはJavaのcontinueに相当する
  • redoは同じブロック引数を使ってもう一度実行する
    • Javaには同様の機能はない
    • 安易に使うと無限ループになるため、抜け出すための条件分岐と併用する

6. メソッド

メソッドとは

  • 概念はJavaと特に変わらない

メソッド呼び出し

  • 概念はJavaと特に変わらない
  • メッセージを受け取るオブジェクトのことを「レシーバ」と呼ぶ
    • Rubyではよく使うがJavaではあまり使われない言葉

関数的メソッド

  • printなどのメソッドは見かけ上はレシーバがないが、記述が省略されているだけ

名前付き引数としてのハッシュ

  • キーワード引数を実現するための実装上のテクニックだが、書き方が古い
  • 今はもっと簡単に書ける
def m(a:, b:, c:)
    p [a, b, c]
end

m(c: 'ccc', b: 'bbb', a: 'aaa')
# => ["aaa", "bbb", "ccc"]

ブロック付きメソッド呼び出し

  • ブロックを受け取るメソッドを実装する際、メソッドの中でyieldと記述するとブロックの内容が実行される
  • ブロック引数がある場合はyieldに渡す
  • 1つのメソッドにブロックは1つしか渡せない

メソッドの別名

  • aliasを使うとメソッドに別名を付けることができる
  • 別名を付ける動機は、Rubyでは既存のメソッドを上書きする等が簡単にできるため、元のメソッドにもアクセスできるように上書き前に別名を付けておくなどが考えられる
演算子メソッド
  • Rubyでは演算子や、配列で使う[]などもメソッド
  • 例えば四則演算子では、左オペランドがレシーバで右オペランドが引数ということ
  • ただ使うだけならメソッドであることは意識する必要はないが、自分で演算子を実装する際などには意識する必要がある

7. クラスとモジュール1

クラスとは

  • クラスの概念はJavaと特に変わらないが、書き方が違う
  • インスタンス生成はnew演算子ではなくnewメソッド
  • 前回も触れたが、classメソッドを使うことでオブジェクトが属しているクラスがわかる

クラスの定義

  • 自分でクラスを定義する際の書き方はJavaと若干違うが、概念としては特に変わらない

initializeメソッド

  • Javaのコンストラクタに相当する
  • 単純にinitializeというメソッドを実装すれば、それがコンストラクタになる
  • initializeの引数はnewメソッドに渡す

インスタンス変数

  • @で始まる名前の変数を書くとそれがインスタンス変数になる
  • インスタンス変数の概念や使い方は特にJavaと変わらない

インスタンスメソッド

  • 概念や使い方は特にJavaと変わらない

アクセスメソッド

  • Javaのアクセサ(getter、setter)に相当する
  • 概念はJavaと変わらないが書き方が大きく異なる
    • インスタンス変数名が@￰nameの場合、getterは「name」、setterは「name=」 と命名する
    • 「=」で終わる名前のメソッドは特別な扱いとなり、obj.name = 'Bob'のように、まるでインスタンス変数に直接アクセスして代入しているかのように見える記述ができる
    • getterについては普通に呼び出すが、通常は()を省略するためobj.nameのようになり、やはりインスタンス変数を直接参照しているかのように見える記述になる
  • 上記はアクセスメソッドを直接実装する場合の書き方だが、通常は自動的に生成させる機能を使う
    • attr_readerはgetterのみ、attr_writerはsetterのみ、attr_accessorは両方を自動生成する
末尾の記号
  • 真偽値を返すメソッドは慣習としてメソッドの名前の末尾を「?」とする
  • レシーバを破壊的に変更するメソッドは慣習としてメソッドの名前の末尾を「!」とする
    • 破壊的に変更するメソッド全てをそのように命名するわけではなく、ある操作について「破壊的に変更する版メソッド」と「破壊的に変更しない版メソッド」が存在する場合、前者のメソッド名の末尾に「!」を付けて区別するということ

宿題

論理演算子について、ショートサーキットではないもの(|や&)も存在するか?

  • 存在する
def a?
    puts 'a'
    true
end

def b?
    puts 'b'
    true
end

a? || b?
# => a

puts '----------'

a? | b?
# => a
# => b

whileなどの構文について、ブロックと同様に処理の範囲を{}で表すことはできるか?

  • できない。シンタックスエラーになる

1つのメソッドにブロックは1つしか渡せないが、代替方法はないか?

def call_proc(p1 ,p2)
    p1.call
    p2.call
end

p1 = Proc.new do
    puts 'p1'
end

p2 = Proc.new do
    puts 'p2'
end

call_proc(p1, p2)
# => p1
# => p2

ブロックを渡すメソッドについて、通常の引数とブロック引数は共存できるか?

  • できる
def parameter_test(a)
    puts a
    yield 'bar'
end

parameter_test('foo') do |b|
    puts b
end
# => foo
# => bar

「=」を名前の末尾に付けるメソッドで代入しないこともできるか?

  • 通常のメソッドのような記法で引数を渡せばできる。引数を渡さないのは不可
class Foo
    def value=(value)
        @value = value
    end

    def value
        @value
    end
end

foo = Foo.new
foo.value=('aaa')
puts foo.value
# => aaa

# foo.value=
# syntax error, unexpected end-of-input

次回

Coming soon
都合により、次回以降の開催はなさそうです。すみません。