Ruby 3.4の文法(リテラル)
Rubyの学び直しとして、文法を確認していきます。
まずはリテラルから。
以下のリファレンスを参考にしています。
リテラルとは
プログラム中に直接記載できる値のことで、数値の 1 や 文字列の 'Hello' などです。
数値リテラル
数値のリテラルには整数や浮動小数点数など複数あります。
数値リテラルは、共通して _ を含めることができます。_ はインタプリタで単に無視されて解釈されるため、桁数をわかりやすくするなどの目的で利用できます。
例: 123_456
_ は数値リテラルの最初と最後では利用できません。また、リテラルの前につけられる符号(+, -)の前後にはつけられません(前後につけた場合はローカル変数やメソッドの名前の一部として解釈されます)。また、 0xなどのプレフィックスの直後には利用できません。また、連続して _ は記載できません。
整数(10進数)
整数は 123 や 0d123 は(10進数の)整数です。
符号をつけることもでき、 +123 や -123 のように記載できます。
浮動小数点数
浮動小数点数は 1.23 、 0.123 などの小数点以下を含む数値です。
小数点以下しかない場合でも 0.1 のように 0 を記載する必要があります。
指数表現
指数で表現する場合、 1.23e-2 や 1.23e+3 のように e の後ろに指数を記載します( 1.23e-2 は 1.23 / 100 = 0.0123 、 1.23e+3 は 1.23 * 1000 = 1230.0 です )。
n進数
2進数
2進数は 0b1010 のように 0b プレフィックスで記載します。
8進数
8進数は 0o147 のように 0o プレフィックスで記載します。
16進数
16進数は 0xffd1 のように 0x プレフィックスで記載します。
有理数
有理数は 123r や 1.23r のように r サフィックスで記載します。
ただし誤解を避けるため、1.23e+4r のように指数部に有理数リテラルを含むことはできません。
複素数(虚数)
複素数(虚数)は 2i や 1.2i のように i サフィックスで記載します。
有理数の複素数(虚数)
有理数の複素数(虚数)は 123ri や 1.23ri のように記載します。
文字列リテラル
文字列リテラルは、 ダブルクォート " かシングルクォート ' のどちらかに囲まれています。
"Hello, World"
'Es geht um einen buch'
ダブルクォートで囲まれた場合、 バックスラッシュ記法や式展開が有効になります。
シングルクォートで囲まれた場合、 \\ と \' を除いて文字列の中身の解釈は行われず、記載されたそのままの文字列となります。
また、スペースで区切って連続で文字列リテラルを記載すると、それらを結合した文字列として解釈されます。
"1" "2"
# 上記は以下と同じ
"12"
バックスラッシュ記法
| バックスラッシュ記法 | 生成される文字 |
|---|---|
| \t | タブ(0x09) |
| \v | 垂直タブ(0x0b) |
| \n | 改行(0x0a) |
| \r | キャリッジリターン(0x0d) |
| \f | 改ページ(0x0c) |
| \b | バックスペース (0x08) |
| \a | ベル (0x07) |
| \e | エスケープ (0x1b) |
| \s | 空白 (0x20) |
| \nnn | 8 進数表記 (n は 0-7) |
| \xnn | 16 進数表記 (n は 0-9,a-f) |
| \cx\C-x | コントロール文字 (x は ASCII 文字) |
| \M-x | メタ x (c |
| \M-\C-x | メタ コントロール x |
| \x | 文字 x そのもの |
| \unnnn | Unicode 文字(n は 0-9 、a-f、A-F、16進数4桁で指定のみ可能) |
| \u{nnnn} | Unicode 文字列(n は 0-9、a-f、A-F のどれか)。nnnnは16進数で1桁から6桁まで指定可能。スペースかタブ区切りで複数の Unicode 文字を指定できる |
| \改行 | 文字列に改行を含めずに文字列リテラル中で改行 |
式展開
ダブルクォートで囲まれた文字列リテラル、コマンド文字列リテラル、正規表現の中では #{式} という形式で式の結果(を文字列化したもの)を埋め込むことができます。
式が変数記号($、@)で始まる変数の場合には {}を省略して、#変数名 という形式でも記載できます。
# に続く文字が { 、$、@でなければ、そのまま文字の # として解釈されます。明示的に式展開を止めるには # の前にバックスラッシュ \ を置きます。
式展開中にもコメントを記載できますが、コメントの終了は } ではなく改行です。
# `#comment }"` はすべてコメントとして解釈されるため、
# 文字列リテラルとしてダブルクォートが閉じていないと解釈される
"#{ 'Hello' # comment }"
# 改行しているので、`# comment` まででコメントが終了して、
# 次の行の ダブルクォートで文字列リテラルが終了していると解釈される
"#{ 'Hello' # comment
}"
文字リテラル
文字リテラルは ? のあとに1文字に当たる表現を指定します。
| 文字リテラル | 生成される文字 |
|---|---|
| ?a | 文字 a を表す文字列。空白などを指定する場合、?\s、?\t などとする必要があります |
| ?あ | 文字 あ を表す文字列 |
| ?\u3042 | 文字 あ を表す文字列。文字のエンコーディングはEncoding::UTF_8に設定されます |
| ?\C-a | コントロール a を表す文字列 |
| ?\M-a | メタ a を表す文字列 |
| ?\M-\C-a | メタ-コントロール a を表す文字列 |
ヒアドキュメント(行指向文字列リテラル)
ヒアドキュメントは ダブルクォート"やシングルクォート'で囲むのではなく、<<識別子 を含む行の次の行から 識別子 だけの行の直前までを文字列として解釈します。
例
<<EOS
Hello,
Ruby
World
EOS
# 上記は以下と同じ
"Hello,\n Ruby\n World\n"
また、開始行となる開始ラベル <<識別子 は、式として機能します。そのため、メソッドの引数や、レシーバとして利用できます。
# 引数として渡すことができる
print("Hello", <<LABEL, 'World')
Ruby
LABEL
# 以下のように標準出力される
# Hello Ruby
# World
# ヒアドキュメントをレシーバにメソッドを呼ぶ
p <<LABEL.upcase
hello ruby world
LABEL
# => "HELLO RUBY WORLD\n"
また1行で複数のヒアドキュメントの記載も可能です(これは p に対して 1番目、2番目の引数として渡されます)。
p <<FIRST, <<SECOND
1つ目
FIRST
2つ目
SECOND
<<-
<<-識別子 を開始行に使うと、終端行をインデントできます。
p <<-EOS
Hello,
Ruby
World
EOS
# ↑ 終端行の識別子をインデントできる
<<~
<<~識別子 を開始業に使うと、最もインデントが少ない行を基準として、すべての行の先頭の空白が削除されます。
ただし、インデントの決定のため、空白やタブのみの行は無視されます。ただし、エスケープされた空白やタブは通常の文字と同じように扱われます。
<<~EOS
This is
an
apple
EOS
# 以下と同じ
"This is\n an \n\n apple\n"
性質の指定
開始ラベルを ダブルクォート"、シングルクォート'、バッククォート ` で囲むことで、対応するリテラルと同じ性質になります。
# ダブルクォートで囲むと、バックスラッシュ記法、式展開が有効になる
<<"EOS"
Hello, #{name}.
EOS
# 上と同じ
<<EOS
Hello, #{name}.
EOS
# 式展開が無効
print <<'EOS'
Hello, #{name}.
EOS
# コマンドを実行
print <<`EOC`
echo 'Hello, World'
EOC
シンボル
シンボルは、Symbolクラスのインスタンスで、文字列と一対一に対応します。
シンボルは文字列と異なり、何度評価されても同じオブジェクトを返します。
また以下のような : をプレフィックスとした表記で定義できます。
:識別子
:変数名
:演算子
定義できる演算子は、再定義可能な演算子に限られます。
例
:class
:foo
:$gvar
:@ivar
:@@cvar
:+
また、 : の後ろを ' や " で囲むことで、任意のシンボルを定義できます。 " で囲んだ場合は、バックスラッシュ記法や式展開が利用できます。
:'foo-bar'
:"or+and"
また%記法( %s{...} )を用いることでも、任意のシンボルが可能になります。
%記法
文字列リテラル、コマンド出力、正規表現リテラル、配列式、シンボルを、 %で始まる以下のような各形式の記法でも記載することができます。
! の部分には改行を含めた任意の非英数字を使うことができます。ただし、%w、%W、%i、%I は区切りとして、空白、改行を用いるため、!の部分には使うことができません。
始まりの区切り文字が括弧((,[,{,<)である時には、終りの区切り文字は対応する括弧(),],},>)になります。括弧を区切り文字にした場合、対応が取れていれば区切り文字と同じ括弧を要素に含めることができます。
-
%!STRING!: ダブルクォートの文字列 -
%Q!STRING!: 同上 -
%q!STRING!: シングルクォート文字列 -
%x!STRING!: コマンド出力 -
%r!STRING!: 正規表現 -
%w!STRING!: 要素が文字列の配列(空白区切り) -
%W!STRING!: 要素が文字列の配列(空白区切り)。式展開、バックスラッシュ記法が有効 -
%s!STRING!: シンボル。式展開、バックスラッシュ記法は無効 -
%i!STRING!: 要素がシンボルの配列(空白区切り) -
%I!STRING!: 要素がシンボルの配列(空白区切り)。式展開、バックスラッシュ記法が有効
正規表現リテラル
/ で囲むことで、正規表現を定義できます。また、%記法でも定義できます。
正規表現内は、バックスラッシュ記法や式展開も有効です。
/^\d{3}-\d{4}$/
また、終りの / の直後に、正規表現のオプションを文字で指定することができます。
-
i: 大文字小文字の区別を行わない -
o: 一度だけ式展開を行う -
x: 空白、改行を無視する。また、バックスラッシュでエスケープしない#から改行までをコメントとみなして無視する(ただし/がコメントに含まれると構文解析エラーとなるため、\/のようにエスケープが必要) -
m: 複数行モードになり、.が改行にもマッチするようになる
式展開がなければ、何度評価されても、同じオブジェクトを返します。式展開がある場合は、評価のたびに正規表現がコンパイルされて正規表現オブジェクトが生成されます。 o オプションが指定されている場合は、同じオブジェクトが返されます。
配列式
配列式はそれぞれ要素として指定された式を評価した結果を要素として持つArrayクラスのインスタンスを返します。
[1, 2, 3]
%記法でも定義できます。
配列式は評価されるたびに毎回新しい配列オブジェクトを生成します。
ハッシュ式
ハッシュ式は、それぞれの式を評価した結果をキーと値とするHashクラスのインスタンスを返します
{ 1 => 'a', 2 => 'b' }
{ 'hello' => 'world', 'foo' => 'bar' }
{ a: 'A', b: 'B' } # { :a => 'A', :b => 'B' } と同じ
{ 'a': 'A', 'b': 'B' } # { a: 'A', b: 'B' } と同じ
メソッドの引数や配列式の末尾に要素が1つ以上のハッシュを渡す場合は、 {, } を省略することができます。
method('a', 5, 'a' => 'A') # method('a', 5, {'a' => 'A'})
['hello' => 'world', 'foo' => 'bar'] # [{'hello' => 'world', 'foo' => 'bar'}]
範囲オブジェクト
条件式以外の場所では、指定された2つの式の間の範囲を示すRangeクラスのインスタンスを返します。
.. は終端を含み、 ... は終端を含みません。
終端を省略して、終端のないRangeオブジェクトを示すことができます。 終端を省略した場合 (1..) は (1..nil) の構文糖になります。ただし、 when 1.. のように記載すると、行が継続するとみなされるため、カッコを付ける必要があります。
条件式での範囲式
条件式で使用された場合、awkやsedなどのようなフリップフロップの挙動をします。
.. の場合
5.times{|n|
if (n==2)..(n==3)
p n
end
}
# => 2
# 3
- 初期状態では式1(始端)だけを評価し、式1が真を返すまでは false を返します。
- 式1が真を返すと true を返します。式2(終端)が真なら初期状態に戻ります。
- この後は式2だけを評価し、式2が真を返すまで true を返します。
- 式2が真を返すと true を返したあと、初期状態に戻ります。
... の場合
5.times{|n|
if (n==2)...(n==3)
p n
end
}
# => 2
# 3
- 初期状態では式1(始端)だけを評価し、式1が真を返すまでは false を返します。
- 式1が真を返すと true を返します。
- この後は式2(終端)だけを評価し、式2が真を返すまで true を返します。
- 式2が真を返すと true を返したあと、初期状態に戻ります。
.. と ... の違い
5.times{|n|
if (n==2)..(n==2)
p n
end
}
#=> 2
5.times{|n|
if (n==2)...(n==2)
p n
end
}
#=> 2
# 3
# 4
コマンド出力
バッククォート(`)で囲まれた文字列は、コマンド実行され、その標準出力の文字列になります。
ダブルクォートで囲まれた文字列と同様にバックスラッシュ記法の解釈と式展開が行なわれたうえで、コマンドが実行されます。
また、コマンドは評価されるたびに実行されます。
コマンドの終了ステータスを得るには、$? を参照します。
%記法 によるコマンド出力もできます。
`date`
%x{ date }
おわりに
普段よく使うリテラル以外は、あまり知らなかったり、よく使うリテラルでも細かい挙動で知らない部分もあり、大変勉強になりました。他の文法についても理解を深めていきたいです。
Discussion