新刊ピックアップ

他の言語経験者がRubyを使い始めると驚くこと

この記事を読むのに必要な時間:およそ 2 分

筆者は現在Rubyプログラマとして働いていますが,もともとはJavaやC#をメインで使っていました。今でこそRubyプログラミングを心の底から楽しめていますが,Rubyを始めた当初はそれまでやってきた言語との違いに戸惑ったものでした。これから新しいプログラミング言語としてRubyを学び始める人も,きっと当時の筆者と同じように驚いたり戸惑ったりすることでしょう。そこで,今回の寄稿記事では他の言語経験者がRubyを使い始めたときに「えっ」と驚くようなポイントをいろいろと挙げてみます。

メソッドの呼び出しの丸かっこが省略できる

Rubyではメソッドを呼び出すときの丸かっこを省略できます。以下はsizeメソッドを丸かっこ付きで呼び出す場合と丸かっこなしで呼び出す場合です(ただし,状況によっては丸かっこを省略できないケースもあります⁠⁠。

"abc".size() #=> 3
"abc".size   #=> 3

nilとfalseだけが偽,それ以外は真

Rubyの真偽値はnil(他の言語で言うところのnullfalseだけが偽で,それ以外のオブジェクト(数値や文字列,配列など)は中身が何であれすべて真です。

数値やnilもすべてオブジェクト

Rubyはオブジェクト指向言語なので数値やnilもすべてオブジェクトです。プログラミング言語によってはオブジェクト指向言語であってもプリミティブ型かそうでないかを意識しなければならないものがありますが,Rubyではそういった考慮は不要です。

# 数値やnilもオブジェクトなのでメソッドが呼び出せる
1.to_s   #=> "1"
nil.to_s #=> ""

ちなみに,Rubyではクラスそのものもオブジェクトになっています。

# to_sメソッドでStringクラスの文字列表現を得る
String.to_s #=> "String"

if文が値を返す

Rubyのif文は実は式になっています。そのためif文の結果を直接変数に代入できます。

n = 1
answer =
  if n > 0
    "正です"
  else
    "0または負です"
  end
answer #=> "正です"

メソッドの戻り値にreturnを付けなくても良い

Rubyのメソッド定義ではreturnを付けなくても最後に評価された式がそのメソッドの戻り値になります。

def add(a, b)
  # return a + bと書いてもいいが,returnなしが主流
  a + b
end
add(1, 2) #=> 3

エイリアスメソッドが定義されていることがある

Rubyではまったく同じ機能なのに名前だけが異なるエイリアスメソッドが定義されていることがあります。たとえば以下のsizelengthのエイリアスメソッドです。

"abc".length #=> 3
"abc".size   #=> 3

配列の添え字に負の値が使える

Rubyでは配列の添え字に負の値を使うと,⁠うしろから数えてn番目」の要素を参照することができます。

arr = [1, 2, 3]
arr[-1] #=> 3

ループ処理にはeachメソッドとブロックを使う

配列をループ処理するような場合はeachメソッドとブロックを使います。ブロックは下のコードでいうと{から}まで囲まれた部分になります。

numbers = [1, 2, 3, 4]
sum = 0
numbers.each { |n| sum += n }
sum #=> 10

ブロックは他の言語で言うところのコールバック関数のような働きをします。たとえば,上のコードをJavaScriptに書き換えるとこんな感じになります。

const numbers = [1, 2, 3, 4]
let sum = 0
numbers.forEach(n => sum += n)
console.log(sum) //=> 10

スクリプト言語なのに静的型検査ができる

Rubyはスクリプト言語なので静的な型検査はできない,と考えている人もおられるかもしれませんが,そんなことはありません。2020年12月にリリースされたRuby 3.0ではRBSと呼ばれる型定義の仕組みが導入されました。

たとえば次のようなRubyスクリプトsample.rbがあったとします。

class Sample
  def add(a, b)
    a + b
  end
end
sample = Sample.new
puts sample.add(1, 2) #=> 3

Sampleクラスのaddメソッドの型情報を定義する場合は,スクリプト本体とは別にRBSファイルsample.rbsを作成します。

class Sample
  def add: (Integer a, Integer b) -> Integer
end

一見,本体のRubyスクリプトによく似ていますが,これはRBSの文法で書かれた型情報です。ここではInteger型の引数を2つ受け取り((Integer a, Integer b)⁠⁠,戻り値としてInteger型の値を返す-> Integer⁠,という型情報が書かれています。

このように型定義情報を書いておくと,Steepという外部ライブラリを使って型検査を行うことができます。ためしに,addメソッドの2つめの引数をわざと文字列にしてみましょう。

puts sample.add(1, "2")

こうするとsteep checkコマンドを実行したときに型エラーが検出されます。

$ steep check
# Type checking files:

..................................F...........................

lib/sample.rb:7:19: [error] Cannot pass a value of type `::String` as an argument of type `::Integer`
│   ::String >: ::Integer
│     ::Object >: ::Integer
│       ::BasicObject >: ::Integer
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└ puts sample.add(1, "2")
                     ~~~

Detected 1 problem from 1 file

型検査が行えるのはコマンドライン上だけではありません。VS CodeやRubyMineのようなエディタ・IDE上で型エラーを検出することもできます。以下はそれぞれVS CodeとRubyMineで型エラーを検出したときの表示例です。

VS Code

VS Code

RubyMine

RubyMine

まとめ

今回の記事では他の言語経験者がRubyを使い始めたときに「えっ」と驚くようなポイントをいくつか挙げてみました。特に,最後に紹介した静的型検査の機能は,最近のRubyの動向をあまりチェックしていなかった人にとってはかなり意外だったのではないでしょうか。

記事の都合上,それぞれのトピックについてあまり深入りはできませんでしたが,2021年12月に発売された拙著プロを目指す人のためのRuby入門 改訂2版では,各トピックをもう少し詳しく説明しています。⁠Rubyがどんな言語なのかもっと詳しく知りたい」という方や,⁠最近のRubyの進化が気になる」という方はぜひ本書を手に取ってみてください。

著者プロフィール

伊藤淳一(いとうじゅんいち)

1977年生まれ。大阪府豊中市出身,兵庫県西脇市在住。
株式会社ソニックガーデンのRailsプログラマ,およびプログラミングスクール「フィヨルドブートキャンプ」のメンター。
ブログやQiitaなどで公開したプログラミング関連の記事多数。説明のわかりやすさには定評がある。
訳書(電子書籍)に「Everyday Rails - RSpecによるRailsテスト入門」(Aaron Sumner 著,Leanpub)がある。
趣味はギター。Rubyを書くのと同じぐらいスラスラとギターが弾けるようになるのが夢。
Twitter:@jnchito
ブログ:https://blog.jnito.com