削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
タグ: 2017年版ソースエディター
Ef3 (トーク | 投稿記録)
→‎制御構造: Crystalの実情に合わせて変更
タグ: 2017年版ソースエディター
451 行
'''[[w:制御構造|制御構造]]'''(せいぎょこうぞう、''control flow'')とは、「順次」「分岐」「反復」という基本的な処理のことを言います。
 
{{コラム|RubyCrystalの真理値|2=
制御構造は「条件式」が真であるか偽であるかによって分岐や反復の振る舞いが変わります。
では「条件式」が真・偽はどの様に決まるのでしょう?
 
RubyCrystalでは <code>false</code> あるいは <code>nil</code> であると偽、それ以外が真です。
 
なので <code>0</code> も <code>[]</code>(空のArray) も <code>{}</code>(空のHash)NamedTuple)も真です。
}}
=== 条件分岐 ===
RubyCrystalの条件分岐には、[[#if|if]], [[#until|until]] と [[#case|case]]の3つの構文があります。
 
==== if ====
'''[[w:if|if]]'''は条件式によって実行・否を切り替える構造構文で、評価した式の値を返すので条件演算子でもあります。
 
;[https://paiza.io/projects/biMpjErLV3TRo004lNGTJg?language=ruby ifの例]:<syntaxhighlight lang="ruby"crystal line>
a = 0.0 / 0.0
 
478 行
end
 
p! (
puts(
if a < 0
"minus"
491 行
</syntaxhighlight>
;表示結果:<syntaxhighlight lang="text">
NaN
(if a < 0
NaN
"minus"
else
if a > 0
"plus"
else
if a == 0
"zero"
else
a
end
end
end) # => NaN
</syntaxhighlight>
:; elsif節:ifは、オプショナルな elsif 節を設け、条件式が偽であった時に別の条件に合致した処理を実行させることが出来ます。
499 ⟶ 511行目:
 
==== 後置のif ====
RubyCrystalには、RubyやPerlのような後置のifがあります。
 
;[https://paiza.io/projects/M72sxlLRG_k29MK1FmgGgQ?language=ruby 後置のifの例]:<syntaxhighlight lang="ruby"crystal>
n = 0
 
511 ⟶ 523行目:
</syntaxhighlight>
 
==== unless====
'''unless'''(アンレスぶん、''unless statement'')は条件式によって実行・否を切り替える構造構文ですが、ifとは条件式に対する挙動が逆です。
 
;[https://paiza.io/projects/6EGyb6ObN49cNkz9GEMwGw?language=ruby unless文の例]:<syntaxhighlight lang="ruby"crystal line>
a = 0.0 / 0.0
 
530 ⟶ 542行目:
 
==== 後置のunless ====
RubyCrystalには、RubyやPerlのような後置のunlessがあります。
 
;[https://paiza.io/projects/tmKKQgJE8prt7y4MbX0wvQ?language=ruby 後置のunlessの例]:<syntaxhighlight lang="ruby"crystal>
n = 0
 
545 ⟶ 557行目:
caseは、複数の条件式によって処理を降る分ける用途の為に用意されています。
 
;[https://paiza.io/projects/zZwUHb2AzrrL346ReD_p1A?language=ruby caseの例]:<syntaxhighlight lang="ruby"crystal line>
n = 2
 
558 ⟶ 570行目:
puts "other"
end
 
p! (
case n
when 1
"one"
when 2
"two"
when 3
"three"
else
"other"
end
)
</syntaxhighlight>
;表示結果:<syntaxhighlight lang="text">
two
(case n
</syntaxhighlight>
when 1
:C言語系のswitch文に慣れた人はbreakがないことに気がつくと思います。Rubyのcaseはfall throughしませんし、fall throughさせる方法もありません。
"one"
when 2
"two"
when 3
"three"
else
"other"
end) # => "two"</syntaxhighlight>
:C言語系のswitch文に慣れた人はbreakがないことに気がつくと思います。Crystalのcaseはfall throughしませんし、fall throughさせる方法もありません。
 
===== when節が定数でなく式を受付ける事を使ったトリック =====
[[#if|if]]を使ったコードをcaseに書き換えてみましょう。
 
;[https://paiza.io/projects/2RNFYYNmA4zCuuPJ8mejEw?language=ruby case true トリック]:<syntaxhighlight lang="ruby"crystal line>
a = 0.0 / 0.0
 
case true
when a < 0
puts "minus"
when a > 0
puts "plus"
when a == 0
puts "zero"
else
puts a
end
p! (
case true
when a < 0
"minus"
when a > 0
"plus"
when a == 0
"zero"
else
a
end
)
</syntaxhighlight>
;表示結果:<syntaxhighlight lang="text">
NaN
(case true
when a < 0
"minus"
when a > 0
"plus"
when a == 0
"zero"
else
a
end) # => NaN
</syntaxhighlight>
このコードは when 節の式の値とcaseの式を <code>===</code> で比較し、最初に一致した when に対応する文が実行される事を利用しています。
589 ⟶ 646行目:
 
=== 繰返し ===
RubyCrystalには、他のプログラミング言語のような[[#繰返し文|繰返し文]]と、[[#イテレーターメソッド|イテレーターメソッド]]があります。
 
==== 繰返し構文 ====
RubyCrystalの繰返し文には、while文 until for文loop文 until2つがあります<ref>for も do-while文は も loop もありません。loopの最後にbreak if 式を設け実現します</ref>。
 
===== while =====
while文(ホワイルぶん、while statement)は条件が'''真'''である間、を実行しつづけます。
;構文:<syntaxhighlight lang="ruby"crystal>
while 条件式 [ do ]
end
</syntaxhighlight>
: Rubyと違い、条件式の後ろに <code>do</code> をつけること省略でき出来せん
 
;[https://paiza.io/projects/FMtf9ld-HN4HPgWLNNAvrA?language=ruby while文のコード例]:<syntaxhighlight lang="ruby"crystal line>
i = 0
p! (
while i < 5 do
while i < 10
puts i
p! i
i += 1
break i if i > 5
end
)
</syntaxhighlight>
: 2行目の <code>i < 5</code>が真の間、次の2行を繰返します。
: 4行目の <code>i += 1</code> は <code>i = i + 1</code> の構文糖
;実行結果:<syntaxhighlight lang="text">
(while i < 10
0
p!(i)
1
i = i + 1
2
if i > 5
3
break i
4
end
end)# =>
i # => 0
i # => 1
i # => 2
i # => 3
i # => 4
i # => 5
6
</syntaxhighlight>
 
===== until =====
until(アンティルぶん、until statement)は条件が'''偽'''である間、を実行しつづけます。whileとは条件に対する挙動が逆です。
;構文:<syntaxhighlight lang="ruby"crystal>
until 条件式 [ do ]
文1
635 ⟶ 704行目:
: <code>do</code> は省略できます。
 
;[https://paiza.io/projects/eAvLT3L3hXe2WJsgqYPWsw?language=ruby untilのコード例]:<syntaxhighlight lang="ruby"crystal line>
i = 0
until i == 3 do
puts i
i += 1
649 ⟶ 718行目:
</syntaxhighlight>
 
===== for =====
RubyCrystalforがありませんが、多くコレクション言語で[[W:Froeach文|froeach文]]イテレーションメソッドを使うこ呼ばれるもの、C言語系の<code>for (;;)</code>とは異なり繰返しを簡素に実現出来ます。
;for文の構文:<syntaxhighlight lang="ruby">
for 変数 in コレクション
end
</syntaxhighlight>
:コレクションは Range, Array, Hash など内部構造を持つオブジェクトです。
 
==== Rangeオブジェクトとfor文 ====
Rangeオブジェクトは、整数の区間を表し範囲演算子 <code>開始 ... 終了</code> で生成します。
 
;コード:<syntaxhighlight lang="ruby"crystal>
rng = 1..3
puts rng.class
rng.each do | n |
for n in rng do
puts "テキスト#{n}番";
end
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
Range(Int32, Int32)
1番
テキスト
2番
テキスト
3番
テキスト
</syntaxhighlight>
 
==== Arrayオブジェクトとfor文 ====
Arrayオブジェクトは、任意の RubyCrystal オブジェクトを要素として持つことができます。
配列式<code>[要素1, 要素2, … 要素n]</code> で生成します。
 
;[https://paiza.io/projects/zwRG10FKO8uQf3tv72C9NQ?language=ruby コード]:<syntaxhighlight lang="ruby"crystal>
animals = ["ネコ", "金魚", "ハムスター"]
 
puts animals.class
animals.each do | animal |
for animal in animals do
puts "動物 #{animal}"
end
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
Array(String)
動物 ネコ
動物 金魚ネコ
動物 金魚
動物 ハムスター
</syntaxhighlight>
 
==== HashNamedTupleオブジェクトとfor文 ====
HashNamedTupleオブジェクトは、任意の RubyCrystal オブジェクトをキーに、任意の RubyCrystal オブジェクトを値に持つことができる連想配列です。
HashNamedTuple式<code>{キー1 => 値1, キー2 => 値2, キーn => 値n}</code> で生成します。
また、キーが Symbol の場合
HashNamedTuple式<code>{キー1: 値1, キー2: 値2, キーn: 値n}</code> で生成することが出来ます。
 
;[https://paiza.io/projects/CeZa9Pg-HLS2I1ijggGkYw?language=ruby コード]:<syntaxhighlight lang="ruby"crystal>
animals = {cat: "ネコ", gold_fish: "金魚", hamster: "ハムスター"}
 
puts animals.class
for en, animal in animals do
animals.each do | en, animal |
puts "動物 #{en}: #{animal}"
end
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
NamedTuple(cat: String, gold_fish: String, hamster: String)
Hash
動物 cat: ネコ
動物 gold_fish: 金魚
714 ⟶ 779行目:
</syntaxhighlight>
 
このように、Rubyのfor文Crystalで多様forがくてもコレクションのメソッドで同様の処理受け付け実現できます。
 
===== loop =====
loop、ありません。
loop文(ループぶん、loop statement)は永久ループを提供します。
while true で代用します。
;構文:<syntaxhighlight lang="ruby">
until [ do ]
文1
文2
文n
end
</syntaxhighlight>
 
;[https://paiza.io/projects/ZB-Ikm3W8SOoKLTlGU161Q?language=ruby loop代用コード例]:<syntaxhighlight lang="ruby"crystal line>
i = 1
while true
loop
puts "0b%b" % i
i <<= 1
break if i > 2**808
end
</syntaxhighlight>
746 ⟶ 804行目:
0b100000000
</syntaxhighlight>
:5行目の、<code>break if i > 2**808</code>でループを脱出するようにしています。この様に break や return あるいは例外が上がらないとループは永久に終わりません。
:このコードは、RubyCrystalにはない do-while文を模倣する例にもなっています。
 
==== イテレーターメソッド ====
===== eachメソッド =====
上述 for を使った配列の処理と、同じ処理を、次のようにコレクションの<code>each</code>メソッドを使っても書けます。
 
;[https://paiza.io/projects/GEmXBCX8GIC27X5U1F1jjw?language=ruby コード]:<syntaxhighlight lang="ruby">
rng = 1..3
puts rng.class
rng.each do
puts "テキスト";
end
 
animals = ["ネコ", "金魚", "ハムスター"]
 
animals.each do |animal|
puts "ペット:#{animal}"
end
 
animals = {cat: "ネコ", gold_fish: "金魚", hamster: "ハムスター"}
 
puts animals.class
animals.each do |en, animal|
puts "動物 #{en}: #{animal}"
end
</syntaxhighlight>
:実行結果:<syntaxhighlight lang="text">
Range
テキスト
テキスト
テキスト
ペット:ネコ
ペット:金魚
ペット:ハムスター
Hash
動物 cat: ネコ
動物 gold_fish: 金魚
動物 hamster: ハムスター
</syntaxhighlight>
 
===== Integer#times =====
Integer#timesは与えられたブロックをオブジェクトの示す整数値回くりかえします。
 
:コード<syntaxhighlight lang="ruby"crystal>
3.times{ puts '"Hello, world!'" }
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
799 ⟶ 820行目:
</syntaxhighlight>
 
;繰返したい処理が2行以上ある場合:<syntaxhighlight lang="ruby"crystal>
3.times {
puts '"Hello'"
puts '"World'"
puts ''""
}
</syntaxhighlight>
817 ⟶ 838行目:
</syntaxhighlight>
 
;[https://paiza.io/projects/tycqR9lC1dCY_rWwjGhYvA?language=ruby ループ変数を使た例]:<syntaxhighlight lang="ruby"crystal>
3.times do |i|
puts "#{i}の倍は#{2 * i}"
828 ⟶ 849行目:
</syntaxhighlight>
 
;ブロックを伴わないtimesメソッド:<syntaxhighlight lang="ruby"crystal>
iter = 3.times
puts iter.class
837 ⟶ 858行目:
</syntaxhighlight>
;実行結果:<syntaxhighlight lang="text">
Int::TimesIterator(Int32)
Enumerator
0
1
2
</syntaxhighlight>
: Integer#times にブロックを渡さないと、EnumeratorInt::TimesIterator([T])オブジェクトが返ります。
: EnumeratorInt::TimesIterator([T])オブジェクトは外部イテレーターと呼ばれnextメソッドで反復を行えます。
 
== 脚註 ==