はじめに

こんにちは!エンジニアの藤井です。このドキュメントは、C# 使いの皆さんのための Ruby 初学用に書かれています。

Ruby でアレはどう書くんだろう?というときに逆引きできるようにしたほか、ほかの人が書いたコードがざっくり読めるような基礎知識も入れました。

少しでも皆さんのお役にたてたら幸いです。

基礎知識

まずは頭に入れておきたい前提条件から。

言語仕様

  • C#はコンパイラ(中間言語(IL)をJITコンパイル)だが、Rubyはインタプリタ。
  • C#は静的型付け言語、Rubyは動的型付け言語。

変数

  • C#はプリミティブ型とObject派生型だが、Rubyはすべてがオブジェクト。
  • クラスでさえClassクラスのインスタンス。
  • 識別子の最初の代入が変数宣言。変数はオブジェクトのコピーでなく参照。

メモリ管理

  • メモリ管理はC#のObjectとほぼ同じ。本体は大体ヒープに置かれる。ガベージコレクションあり、デストラクタは基本不要(必要に応じてファイナライザを書く)。

文末

  • 文末は改行かセミコロン(;)。ワンライナーにしたいときくらいしかセミコロンは使わない。
  • 複数行にわたって文を書きたいときは、スラッシュ(/)を使う。もしくは、演算子やピリオド(.)で行が終われば文が不完全なので、複数行が認められる。

予約語

BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true     __LINE__
begin    else     in       rescue   undef    __FILE__
break    elsif    module   retry    unless   __ENCODING__
case     end      next     return   until

コメント

#コメント

# frozen_string_literal: true
# ↑文字列リテラルをすべて変更出来ないようにする指示。
# こういう指示を行うコメントをマジックコメントと言う。

=begin
  複数行コメント
  =begin と =end は必ず行頭(インデントなし)に記述する必要がある。
=end

リテラル

  • C#の null は nil と書く。
  • Rubyでは、リテラルもオブジェクト。nilもオブジェクト。nil.size とかできる。

数値リテラル

  • C# と同じ。
num = 0d1234       // 10進数 (0dで始まる数値は10進数とみなされる)
num = 0xffff       // 16進数 (0xで始まる数値は16進数とみなされる)
num = 0o777        //  8進数 (0oで始まる数値は 8進数とみなされる)
num = 0b11000100   //  2進数 (0bで始まる数値は 2進数とみなされる)
num = 1.234        // 浮動小数点数
num = 1.2e3        // 浮動小数点数(指数表記) 1.2 × 10の3乗

文字列リテラル

  • char型はない。文字列(String)型のみ。
  • シングルクォート('xxx') :式展開、エスケープが無効。C# の @"xxx"。
  • ダブルクォート("xxx") :式展開、エスケープが有効。C# の "xxx"、$"xxx"

式展開

  • ダブルクォートや正規表現リテラルなどで式展開できる。
"my name is #{$ruby}" #=> "my name is RUBY"
'my name is #{$ruby}' #=> "my name is #{$ruby}"

正規表現リテラル

  • スラッシュ(/)で囲まれた文字列は正規表現。

コマンド出力

  • バッククォート(`)で囲まれた文字列はコマンドとして実行され、その標準出力が文字列の値となる。コマンドの終了ステータス(Process::Status オブジェクト)は、$? にセットされる。

ヒアドキュメント

  • 改行を含む文字列リテラル。C#の """に近い。
  • <<識別子 で開始。次の行から文字列を書いていき、最後に同じ 識別子 だけの行を書けば、ヒアドキュメントの出来上がり。
  • 次の行、というのがミソで、その行は何を書いても文字列には含まれないから、メソッドの途中とかにも使える。
  • <<-識別子 とか、<<~識別子で開始すると、インデントが無視される。
hoge( <<TEXT1, 10, <<TEXT2 )
ここに文章を書く。
改行も入れられる。
TEXT1
何個でもいける
TEXT2

hoge( <<-TEXT,  10)
最後の識別子をインデントしたいときはこう書く。
    TEXT

hoge( <<~TEXT,  10)
        文字列をインデントしたいときはこう書く。
            このインデントは一段深いまま。
        一番浅いインデントまでが無視される。
    TEXT

hoge( <<"TEXT" , 10)
式展開される。デフォルトは式展開される。 #{$price}.
TEXT

hoge( <<'TEXT' , 10)
式展開されない。 #{$price}.
TEXT

演算子

べき乗演算子

  • べき乗演算子 (**)があります。C#のMath.Pow()。

宇宙船演算子

  • 宇宙船演算子 (<=>): 左辺が大きければ 1(または正の整数)、等しければ 0、小さければ -1 (または負の整数)を返す。 IComparable.CompareTo みたいな感じ。比較できなければ nil を返す。

論理演算子

  • && 、||、!の他に and 、 or 、notという英字の演算子あり。これらは記号版よりも、代入よりも優先順位が低いので、(a = b or raise "error")のように制御構造に使うことが多い。
# && は代入より優先度が高い
result = true && false 
# result => false

# and は代入より優先度が低い
result = true and false
# (result = true) and false と評価される
# result => true

nil ガード

  • x ||= 10 のように書くと、x が nil または false の場合にのみ 10 を代入する。(x = x || 10)と同じ。C# の ??= に近い。

ぼっち演算子

  • x&.hoge のように書くと、x が nil の場合 hoge メソッドを呼ばない。

スプラット演算子

  • *(アスタリスク)はスプラット演算子といい、Range(後述)を分解して配列にする。可変長引数に便利。** は、ハッシュ(後述)を分解する。
[ *1..5 ] #=> [ 1, 2, 3, 4, 5 ] スプラット展開
options = { color: "red", size: "large" }
new_config = { id: 1, **options } # => { id: 1, color: "red", size: "large" }

ケース等価演算子

  • === をケース等価演算子と呼び、case 文の内部で使われている。
  • 右側のオブジェクトが、左側のグループ(集合・範囲・クラス)に含まれているかを判定する演算子。
(1..10) === 5    # true  5は1〜10の範囲内
(1..10) === 15   # false 15は1〜10の範囲外
String === "hoge"   # true  "hoge" は String クラス
Integer === 10      # true  10 は Integerクラス
Numeric === 10      # true  IntegerはNumericのサブクラス
/^[0-9]+$/ === "123"  # true  正規表現にマッチ
/^[0-9]+$/ === "abc"  # false 正規表現にマッチしない

インクリメント

  • i++ や --i はありません。i += 1、i -= 1 と書く。

三項演算子

  • あります。

ビット演算子

  • あります。

typeof

  • .classメソッド、is_a メソッドを使う。

ポインタ

  • .object_id メソッドを使う。

sizeof

  • .size メソッドを使う。

記号の意味がわからないとき

enum

  • ありません。シンボル(後述)を使おう。もしくはモジュールやクラスとして自作しよう。
  • Ruby on Rails なら ActiveRecord::Enum を使うのもよい。

構造体

  • ハッシュを使うのが一般的。
  • もしくはStructクラス、Dataクラスを使う。

変数

宣言

  • 識別子への最初の代入が変数宣言。初期値はnil。
  • 代入せずに使うと NameError 例外。
  • 代入が行われなくても、宣言は有効。
v = 1 if false    # 代入は行われないが宣言は有効
p defined?(v)     # => "local-variable"
p v               # => nil

識別子

  • 識別子の最初1文字が英大文字なら定数、そうでなければ変数。

定数

  • いわゆる定数は全部大文字とし、クラス名やモジュール名はキャメルケースが多い(クラスはClassクラスのインスタンスなので、変数名として扱われる)。
  • const はない。
  • 警告(Warning) は出るが、定数に値を代入することも一応可能。
  • readonly は .freezeメソッド(ちょっと違う、Frozenクラスみたいなの)を使う。

変数のスコープ

  • 先頭1文字でスコープが変わる。
  • 通常スネークケース。
  • ローカル変数 先頭英小文字か_(アンダースコア)。スコープは基本ブロック内。
  • インスタンス変数 先頭が @。C# のフィールド。プロパティみたいにすることもできる(後述)。スコープはそのインスタンス内。
  • クラス変数 先頭が @@。C# の static フィールド。スコープはそのクラス、サブクラス内。
  • グローバル変数 先頭が $ 。
  • スレッドローカル変数 Thread.current[:key] = value のように記述する変数は、そのスレッド内だけで保持され、他のスレッドからは見えない。

組み込み変数

範囲(Range)

Range クラスのインスタンス。

5.times{|n|
  if (n==2)...(n==2)
    p n
  end
#=> 2
#   3
#   4

配列(Array)

Rubyの配列は、C# の配列というより、List<object> のように柔軟。

配列の初期化

  • 空の配列: arr = []
  • 値を指定: arr = [1, 2, "apple"]
  • 多次元: arr = [[1, 2], [3, 4]]
  • ジャグ: arr = [[1, 2], [3]]
  • 最後が, (カンマ)でもOK
  • 余っても無視される
    a, b = 100, 200, 300
    a = 100
    b = 200
  • あまりを配列で引き受ける *(アスタリスク)
    a, *b, c = 100, 200, 300, 400
    a = 100
    b = [ 200, 300 ]
    c = 400

簡略記法

  • 文字列の配列 %w を使うと引用符やカンマを省略できる。
    %w(apple orange grape) => ["apple", "orange", "grape"]
  • シンボル(後述)の配列  %i を使う。
    %i(a b c) => [:a, :b, :c]

コンストラクタ

  • サイズのみ指定
    Array.new(3) #=> [nil, nil, nil]
  • サイズとデフォルト値を指定
    Array.new(3, 0) #=> [0, 0, 0]
  • デフォルト値の注意点
    同じオブジェクトを指すので注意。
    a = Array.new(3, "aa") #=> ["aa", "aa", "aa"]
    a[1].uppercase!
    a #=> ["AA", "AA", "AA"]
  • ブロックを使う
    Array.new(3) { "default" }
  • 範囲(Range)から作成
    (1..5).to_a #=> [1, 2, 3, 4, 5]
    [ *1..5 ] #=> [ 1, 2, 3, 4, 5 ] スプラット展開
  • 引数から作成
    Array(1..3) => [1, 2, 3]
  • 要素を計算して作成
    Array.new(5) { |n| n * 2 } => [0, 2, 4, 6, 8]

要素の取得

a = [ 1, 2, 3, 4, 5 ]のとき

  • a[1] #=> 2 #0始まり
  • a[-2]  #=> 4 #うしろから2要素目
  • a(1,3) #=> [ 2, 3, 4 ]  #位置,長さ
  • a.values_at( 0, 2, 4 ) #=> [ 1, 3, 5 ]
  • a[a.size-1] #=> 5 #最後の要素
  • a.last #=> 5 #最後の要素
  • a.last(2) #=> [ 4, 5 ]  # 最後の2要素
  • a.first #=> 1 # 最初の要素
  • a.first(2) #=> [ 1, 2 ]  # 最後の2要素

要素の変更

a = [ 1, 2, 3, 4, 5 ]のとき

  • a[-2] = 10
    a  #=> [ 1, 2, 3, 10, 5 ]
  • a[6] = 20
    a  #=> [ 1, 2, 3, 10, 5, nil, 20 ]
  • a[1, 5] = 30
    a  #=> [ 1, 30, 20 ]

要素の追加

a = [ 1, 30, 20 ]のとき

  • a << 100 << 200
    a  #=> [ 1, 30, 20, 100, 200 ]
  • a.push(300,  400)
    a  #=> [ 1, 30, 20, 100, 200, 300, 400]

配列の連結

a = [1]、b = [2, 3] のとき

  • a + b #=> [ 1, 2, 3 ] 非破壊的
  • a.concat(b) #=> [ 1, 2, 3 ] aを破壊

配列の論理演算

a = [1, 2, 3]、b = [3, 4, 5] のとき

  • a - b #=> [ 1, 2 ]
  • a | b #=> [ 1, 2, 3, 4, 5 ]
  • a & b #=> [ 3 ]

ハッシュ(Dictionary)

ハッシュの初期化

  • シンボルキー(推奨)。どちらの書き方でも同じ。
    map = { name: "Alice", age: 25 }
    map = { :name => "Alice", :age => 25 }
  • 文字列やオブジェクトなどをキーにするときは、=>(ハッシュロケット)で指定。
    map = { "name" => "Alice", "age" => 25 }
  • ブロックで初期化
    map = Hash.new { |hash, key| hash[key] = 0 }

値の取得

  • map[ :name ]
  • map[ “name” ]
  • キーがなくても例外にならない。デフォルトではnilを返すが、Hash.new("hoge")で返す値を変えられる。

キーの比較

  • キーの比較には hash メソッドと eql? メソッドを使う。
  • デフォルトでは別のインスタンスだと別のキーと見なされるので、必要に応じて両メソッドをオーバーライドする。

シンボル

  • enum, #define みたいに使うが、文字列と互換できる性質を持つ。
  • 数値なので、メモリはあまり食わない。とはいえ#defineのようなプリプロセッサとは違い実体があるので、あまり作り過ぎるとまずい。

シンボルの名前

  • :apple 識別子として有効な文字列でつくる。
  • :'apple' 文字列からつくる。
  • :"$(name.upcase)" 式展開してつくる。
  • これまた宣言はいらないので、次のように生成できる。
    hash = { apple: 10, orange: 5 }

シンボルの%記法

  • 下記は同じ意味。シンボルにはスペースを含められる。
    %s!i am symbol!
    %s(i am symbol)
    :"i am symbol"
  • シンボルの配列をつくる。下記は同じ意味。
    %i(apple orange melon)
    [:apple, :orange, :melon]

文字列との関係

  • str.to_sym で文字列をシンボルに変換できる。
  • sym.to_s でシンボルを文字列に変換できる。

まとめ

前編では、Ruby の基礎知識に加え、基本的な型について説明しました。後編では、さらにディープなRubyにせまっていきます。