Ruby Language
制御フロー
サーチ…
if、elsif、else、end
Rubyは、 end
キーワードで終わる、分岐論理のための期待されるif
とelse
式を提供します:
# Simulate flipping a coin
result = [:heads, :tails].sample
if result == :heads
puts 'The coin-toss came up "heads"'
else
puts 'The coin-toss came up "tails"'
end
Rubyでは、 if
文は値に評価される式であり、結果は変数に代入できます。
status = if age < 18
:minor
else
:adult
end
RubyはCスタイルの三項演算子も提供しています( 詳細はこちらを参照 )。
some_statement ? if_true : if_false
つまり、if-elseを使用した上記の例は、次のように書くこともできます。
status = age < 18 ? :minor : :adult
さらに、Rubyはelsif
キーワードを提供しています。これは、追加の分岐ロジックを有効にするための式を受け入れます:
label = if shirt_size == :s
'small'
elsif shirt_size == :m
'medium'
elsif shirt_size == :l
'large'
else
'unknown size'
end
if
/ elsif
チェーンの条件が真でなく、 else
節がない場合、式はnilと評価されます。 nil.to_s
は空文字列なので、 nil.to_s
は文字列補間の中で便利です:
"user#{'s' if @users.size != 1}"
真実と偽の価値
Rubyでは、「偽」とみなされる正確に2つの値があり、 if
式の条件としてテストされたときにfalseを返します。彼らです:
-
nil
- ブール値
false
他のすべての値は、以下を含む「真実」とみなされます。
-
0
- 数値ゼロ(整数またはその他) -
""
- 空文字列 -
"\n"
- 空白のみを含む文字"\n"
-
[]
- 空の配列 -
{}
- 空のハッシュ
例えば、次のコードを考えてみましょう:
def check_truthy(var_name, var)
is_truthy = var ? "truthy" : "falsy"
puts "#{var_name} is #{is_truthy}"
end
check_truthy("false", false)
check_truthy("nil", nil)
check_truthy("0", 0)
check_truthy("empty string", "")
check_truthy("\\n", "\n")
check_truthy("empty array", [])
check_truthy("empty hash", {})
出力:
false is falsy
nil is falsy
0 is truthy
empty string is truthy
\n is truthy
empty array is truthy
empty hash is truthy
〜まで、
while
ループは、指定された条件が満たされている間にブロックを実行します。
i = 0
while i < 5
puts "Iteration ##{i}"
i +=1
end
until
ループは、条件がfalseの間にブロックを実行します。
i = 0
until i == 5
puts "Iteration ##{i}"
i +=1
end
インラインif / unless
一般的なパターンは、インラインで、または末尾を使用することであるif
又はunless
:
puts "x is less than 5" if x < 5
これは条件付き修飾語として知られており、簡単なガードコードと早期返品を追加する便利な方法です:
def save_to_file(data, filename)
raise "no filename given" if filename.empty?
return false unless data.valid?
File.write(filename, data)
end
これらの修飾子にelse
節を追加することはできません。また、一般的にメインロジック内で条件修飾子を使用することはお勧めしません。複雑なコードのif
、通常のif
、 elsif
、 else
代わりに使用する必要があります。
限り
一般的なステートメントはif !(some condition)
です。 Rubyは、 unless
ステートメントの代替案を提供しています。
構造体は、条件が負であることを除いて、 if
文とまったく同じです。また、 unless
文はelsif
サポートしていませんが、 else
サポートしていelse
:
# Prints not inclusive
unless 'hellow'.include?('all')
puts 'not inclusive'
end
ケースステートメント
Rubyはswitch文にcase
キーワードを使用します。
case文は、
case
引数の位置にあるオプションの条件と、when
節の0個以上の条件から構成されます。条件に一致する最初のwhen
句(または条件がnullの場合はブール値の真理値に評価する)が「勝ち」、そのコードスタンザが実行されます。 case文の値は成功したwhen
節の値です。そうした節がない場合はnil
です。case文は、
else
節で終了することができelse
。ステートメントがカンマで区切られた複数の候補値を持つことができるそれぞれのwhen
。
例:
case x
when 1,2,3
puts "1, 2, or 3"
when 10
puts "10"
else
puts "Some other number"
end
短いバージョン:
case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end
case
節の値は、各when
節で===
メソッド(not ==
)を使用して一致します。したがって、さまざまな種類のオブジェクトで使用できます。
case 17
when 13..19
puts "teenager"
end
case "google"
when /oo/
puts "word contains oo"
end
case
文は、 Procまたはlambdaで使用できます。
case 44
when -> (n) { n.even? or n < 0 }
puts "even or less than zero"
end
クラスではcase
ステートメントを使用できます。
case x
when Integer
puts "It's an integer"
when String
puts "It's a string"
end
===
メソッドを実装することで、独自のマッチクラスを作成することができます:
class Empty
def self.===(object)
!object or "" == object
end
end
case ""
when Empty
puts "name was empty"
else
puts "name is not empty"
end
case
文は、一致する値を指定せずに使用できます。
case
when ENV['A'] == 'Y'
puts 'A'
when ENV['B'] == 'Y'
puts 'B'
else
puts 'Neither A nor B'
end
case
ステートメントには値があるので、メソッドの引数または代入として使用できます。
description = case 16
when 13..19 then "teenager"
else ""
end
ブレーク、次、およびやり直しによるループ制御
Rubyブロックの実行フローは、 break
、 next
、 redo
ステートメントで制御できます。
break
break
ステートメントはブロックを直ちに終了します。ブロック内の残りの命令はスキップされ、反復は終了します。
actions = %w(run jump swim exit macarena)
index = 0
while index < actions.length
action = actions[index]
break if action == "exit"
index += 1
puts "Currently doing this action: #{action}"
end
# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
next
next
ステートメントはすぐにブロックの先頭に戻り、次の繰り返しに進みます。ブロック内の残りの命令はスキップされます。
actions = %w(run jump swim rest macarena)
index = 0
while index < actions.length
action = actions[index]
index += 1
next if action == "rest"
puts "Currently doing this action: #{action}"
end
# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
# Currently doing this action: macarena
redo
redo
文はブロックのすぐ上に戻り、同じ反復を再試行します。ブロック内の残りの命令はスキップされます。
actions = %w(run jump swim sleep macarena)
index = 0
repeat_count = 0
while index < actions.length
action = actions[index]
puts "Currently doing this action: #{action}"
if action == "sleep"
repeat_count += 1
redo if repeat_count < 3
end
index += 1
end
# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
# Currently doing this action: sleep
# Currently doing this action: sleep
# Currently doing this action: sleep
# Currently doing this action: macarena
Enumerable
繰り返し
ループに加えて、これらのステートメントは、 each
やmap
などのEnumerable反復メソッドで動作します。
[1, 2, 3].each do |item|
next if item.even?
puts "Item: #{item}"
end
# Item: 1
# Item: 3
結果値をブロックする
break
文とnext
文の両方で、値を指定してブロック結果値として使用します。
even_value = for value in [1, 2, 3]
break value if value.even?
end
puts "The first even value is: #{even_value}"
# The first even value is: 2
スロー、キャッチ
他の多くのプログラミング言語とは異なり、 throw
キーワードとcatch
キーワードはRubyの例外処理とは関係ありません。
Rubyでは、他の言語のラベルと同様にthrow
してcatch
ます。これらは制御フローを変更するために使用されますが、例外のような「エラー」の概念には関係しません。
catch(:out) do
catch(:nested) do
puts "nested"
end
puts "before"
throw :out
puts "will not be executed"
end
puts "after"
# prints "nested", "before", "after"
論理文による制御フロー
直観に反するように見えるかもしれませんが、論理演算子を使って文が実行されているかどうかを判断できます。例えば:
File.exist?(filename) or STDERR.puts "#{filename} does not exist!"
これは、ファイルが存在するかどうかを確認し、エラーメッセージがない場合にのみ表示します。 or
文は、それはそれはそれは価値のかどうか真か偽であるのは間違いないだろう一度実行を停止します意味し、怠け者です。第1項が真であるとすぐに、他の項の価値をチェックする必要はありません。しかし、第1項が偽であれば、第2項をチェックしなければならない。
一般的な使い方は、デフォルト値を設定することです:
glass = glass or 'full' # Optimist!
それはまだ設定されていない場合、 glass
の値を 'フル'に設定します。より簡潔には、 or
シンボリックバージョンを使用することができます:
glass ||= 'empty' # Pessimist.
また、最初の文がfalseの場合にのみ、2番目の文を実行することもできます。
File.exist?(filename) and puts "#{filename} found!"
ここでも、 and
必要な場合にのみ値に到達する第二の文を実行しますので、怠け者です。
or
演算子は、 and
よりも優先度が低くand
ます。同様に、 ||
&&
よりも優先順位が低くなります。シンボルフォームは、ワードフォームよりも優先順位が高くなります。これは、このテクニックと割り当てをいつ組み合わせるかを知るために便利です:
a = 1 and b = 2
#=> a==1
#=> b==2
a = 1 && b = 2; puts a, b
#=> a==2
#=> b==2
Rubyスタイルガイドでは以下を推奨しています。
and
とor
キーワードは禁止されています。読みやすさを最小限にすることは、微妙なバグを導入する高い可能性に値するものではありません。ブール式の場合、常に&&
と||
使用します。代わりに。フロー制御のif
、if
とunless
使用します。&&
と||
許容されるがあまり明確ではない。
開始、終了
begin
ブロックは、複数のステートメントをグループ化する制御構造です。
begin
a = 7
b = 6
a * b
end
begin
ブロックはブロック内の最後のステートメントの値を返します。次の例は、 3
を返します。
begin
1
2
3
end
begin
ブロックは、結果を返すために複数のステートメントが必要な場合がある||=
演算子を使用した条件付き代入に便利です。
circumference ||=
begin
radius = 7
tau = Math::PI * 2
tau * radius
end
また、 rescue
、 ensure
、 while
、 if
、 unless
などの他のブロック構造と組み合わせて、プログラムフローをより詳細に制御することもできます。
Begin
ブロックは{ ... }
やdo ... end
ようなコードブロックではありません。関数に渡すことはできません。
return対next:ブロック内の非ローカル戻り
この壊れたスニペットを考えてみましょう:
def foo
bar = [1, 2, 3, 4].map do |x|
return 0 if x.even?
x
end
puts 'baz'
bar
end
foo # => 0
map
のブロック結果の配列の値をreturn
ことが期待されるかもしれません。したがって、 foo
の戻り値は[1, 0, 3, 0]
foo
[1, 0, 3, 0]
ます。代わりに、 return
はメソッドfoo
から値を返します 。 baz
は印刷されていないことに注意してください。これは実行が決してその行に達していないことを意味します
next
価値があるのはトリックです。これはブロックレベルのreturn
として機能します。
def foo
bar = [1, 2, 3, 4].map do |x|
next 0 if x.even?
x
end
puts 'baz'
bar
end
foo # baz
# => [1, 0, 3, 0]
ない場合にはreturn
、ブロックによって返された値は、その最後の式の値です。
等号/条件付き代入演算子(|| =)
Rubyには、変数がnil
またはfalse
いずれかに評価される場合にのみ、変数に代入できるようにする等号演算子があります。
||= # this is the operator that achieves this.
この演算子は、二重パイプがorを表し、そして等号は値の代入を表します。あなたはそれが次のようなものであると考えるかもしれません:
x = x || y
この上の例は正しくありません。 or-equals演算子は、実際にはこれを表します。
x || x = y
x
がnil
またはfalse
評価された場合、 x
はy
の値が割り当てられ、それ以外の場合は変更されません。
これは、等号演算子の実際の使用例です。ユーザーに電子メールを送信する予定のコードの一部があるとします。これまで何の理由であれ、このユーザーの電子メールがない場合はどうしますか?あなたは次のようなものを書くかもしれません:
if user_email.nil?
user_email = "[email protected]"
end
or-equals演算子を使用して、このコード全体をカットして、きれいで明確な制御と機能を提供します。
user_email ||= "[email protected]"
false
が有効な値である場合は、 false
てそれを上書きしないように注意する必要があります。
has_been_run = false
has_been_run ||= true
#=> true
has_been_run = false
has_been_run = true if has_been_run.nil?
#=> false
三項演算子
Rubyには三項演算子( ?:
:)があり、条件が真理として評価される場合に基づいて2つの値の1つを返します。
conditional ? value_if_truthy : value_if_falsy
value = true
value ? "true" : "false"
#=> "true"
value = false
value ? "true" : "false"
#=> "false"
三つ目が優先されるが、 if a then b else c end
書き込むことと同じである
例:
puts (if 1 then 2 else 3 end) # => 2
puts 1 ? 2 : 3 # => 2
x = if 1 then 2 else 3 end
puts x # => 2
フリップフロップ演算子
フリップフロップ演算子..
は、条件文の2つの条件の間で使用され..
(1..5).select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 3, 4]
条件は、最初の部分がtrue
なるまで false
評価されtrue
。次に、2番目の部分がtrue
なるまで true
に評価されtrue
。その後、再びfalse
に切り替わります。
この例は、何が選択されているかを示しています。
[1, 2, 2, 3, 4, 4, 5].select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 2, 3, 4]
フリップフロップ演算子のみ(含む内部IFS動作しunless
)と三項演算子を。それ以外の場合は範囲演算子と見なされます。
(1..5).select do |e|
(e == 2) .. (e == 4)
end
# => ArgumentError: bad value for range
それはfalse
からtrue
、そして複数回後方に切り替えることができtrue
:
((1..5).to_a * 2).select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 3, 4, 2, 3, 4]