はじめに
こんにちは!エンジニアの藤井です。このドキュメントは、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 メソッドを使う。
記号の意味がわからないとき
- 公式ドキュメントが便利。
Rubyで使われる記号の意味
https://docs.ruby-lang.org/ja/latest/doc/symref.html
型
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 のように記述する変数は、そのスレッド内だけで保持され、他のスレッドからは見えない。
組み込み変数
- グローバル変数のうち、 Ruby 処理系によって特殊な意味を与えられているもの。$DEBUG(デバッグモード)とか、$$ (プロセスID)とかがある。
- Kernel モジュール参照。
https://docs.ruby-lang.org/ja/latest/class/Kernel.html
範囲(Range)
Range クラスのインスタンス。
- (1..10) 最後の値を含む。
- (1...10) 最後の値を含まない。
- (1..) は (1..nil) のシンタックスシュガー。
- 条件式としても使えますが、複雑なので下記参照のこと。
演算子式/範囲式
https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html#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にせまっていきます。
