小ワザ
if 命令 †
if 命令は実行する文にたいして条件を設け、条件の成立(真)・不成立(偽)によって処理を分岐させる構文命令。
関連トピック
HSPでのif文の書き方についてです。
- 二者択一
1
2
3
4
5
6
7
8
9
|
-
|
!
-
|
!
| n = 5
if n = 0{
mes "nは0です"
}
else{
mes "nは0ではありません"
}
stop
|
- 三者択一(悪い例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
-
|
!
-
-
|
!
-
|
!
!
| n = 5
if n < 0{
mes "nは0未満です"
}
else{
if n > 0{
mes "nは0より大きいです"
}
else{
mes "nは0です"
}
}
stop
|
初心者はif文のネストが深くすることをカッコイイと思う傾向があります。
僕も最初はネスティングを美しいと感じていましたが、ある本*1をきっかけに「美」の価値観が変わりました。
ネスティングはバグの元です。
初心者のうちから見かけに騙されないコーディングをするべきだと思います。
- 三者択一(間違い例)
1
2
3
4
5
6
7
8
9
10
11
|
-
|
!
-
|
-
|
!
| n = 5
if n < 0 {
mes "nは0未満です"
}
if n > 0 {
mes "nは0より大きいです"
} else {
mes "nは0です"
}
stop
|
最初の条件で0未満をチェックしたので2番目の条件式で0より大きい数字をチェックしている。
0未満と0より大きい数字をチェックしてどちらも不成立だったのでelseでnを0と断言しています。
がこれは間違いです。最初の条件式と2番目の条件式は別々に評価されます。
nがマイナスの値だった時、最初の条件式では成立して正しいメッセージが表示されます。
2番目の条件式では不成立なのでelseに移って間違った結果を表示してしまいます。
- 三者択一(悪くない例1*2)
1
2
3
4
5
6
7
8
9
10
11
12
|
-
|
!
-
|
!
-
|
!
| n = 5
if n < 0 {
mes "nは0未満です"
}
if n > 0 {
mes "nは0より大きいです"
}
if n = 0 {
mes "nは0です"
}
stop
|
if文は条件式が成り立たなければその条件内の処理を無視して次の条件に移ります。
- 三者択一(悪くない例2)
1
2
3
4
5
6
7
|
| n = 5
if n < 0 : mes "nは0未満です"
if n > 0 : mes "nは0より大きいです"
if n = 0 : mes "nは0です"
stop
|
悪くない例2をHSPっぽく短縮形*3で書いたものです。
バージョンアップなどで条件内の処理が増えたときのことを考えた時には悪くない例1で書いてあると、
ブレース*4を書く手間も省けます。しかし、どちらがいいというわけではありません。
- 三者択一(読みにくい例)
1
2
3
4
5
|
| n = 5
if n<0:mes "nは0未満です":else:if n>0 :mes "nは0より大きいです":else:mes "nは0です"
stop
|
*都合によりスペースを詰めています。
HSPらしく書いてるつもりですがこれは読みにくい例です。
ちょっと発見したワザなので置いておきます。まずif-else構文は次のように書けます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
-
|
-
|
!
-
|
-
-
|
-
|
!
!
| a = 5
if (a = 0) : mes "a = 0" : else : mes "a != 0"
if (a = 0) {
mes "a = 0"
} else {
mes "a != 0"
}
b = 4
if (b = 0) : mes "b = 0" : else : if (b = 5) : mes "b = 5": else : mes "b!0 & b!5"
if (b = 0) {
mes "b=0"
} else {
if (b = 5) {
mes "b = 5"
} else {
mes "b!0 & b!5"
}
}
|
2行目と10行目はマルチステートメントを使って1行に収める書き方で、その下は複数行でブロック {...} を対応させた丁寧な書き方です。
次に10行目の『 else : if (b = 5) 』に注目してください。else節で更にif文を使っています。
というわけで11行目〜19行目をこのように書き換えられます。
1
2
3
4
5
6
7
| -
|
-
|
-
|
!
| if (b = 0) {
mes "b = 0"
} else : if (b = 5) {
mes "b = 5"
} else {
mes "b!0 & b!5"
}
|
他の言語では『 else : if 』という文に「elsif」や「elseif」といった予約語を用意しています*5。
正直「else : if」はタイプが多いので、Perl風な記述ができるようにマクロで置き換えるとこう書けます。
1
2
3
4
5
6
7
8
9
|
-
|
-
|
-
|
!
| #define elsif(%1) else : if %1
if (b = 0) : mes "b = 0" : elsif b = 5 : mes "b = 5": else : mes "b!0 & b!5"
if (b = 0) {
mes "b = 0"
} elsif (b = 5) {
mes "b = 5"
} else {
mes "b!0 & b!5"
}
|
インデントの膨張も抑えられ、タイプも抑えられて結構使えます。
こういった小さく使えるマクロなどはファイル毎に定義しなくてもいいようにしたいですよね。
というわけでその方法も合わせて紹介します。(ガイドに詳細に載っているので簡単に。)
HSPのインストールディレクトリのcommonフォルダの中に「userdef.as」というファイルを用意します。
ファイルを開いて
#define global elsif(%1) else : if %1
と書いて保存してください。
これで「#include "userdef.as"」などと記述しなくても自動で読み込まれて、elsif を使えるようになります。
ただこのままではいつでも使えてしまいます。(HSP標準の文法に準拠しない。)
というわけで私は[HSP拡張マクロを使用する]のチェックの有無によって使用可/使用不可を切り替えたいので
#ifdef __hspdef__
#define global elsif(%1) else : if %1
#endif
と書いてこれから使っていきます。
ただし、userdef.as に書いたマクロなどを使ったスクリプトを人に見せても「なんだこの単語は?」となりますので要注意です。
( elsifなら気づいてくれそうだけど。)
1
2
3
4
5
6
7
8
9
10
|
-
|
!
-
|
!
-
|
!
| n = 0 if (n < 0) {
mes "nは0未満です"
}
if (n > 0) {
mes "nは0より大きいです"
}
if (n = 0) {
mes "nは0です"
}
|
常に3回比較されます。
|
1
2
3
4
5
6
7
8
9
10
|
-
|
-
-
|
-
|
!
!
| n = -1 if (n < 0) {
mes "n < 0"
} else {
if (n > 0) {
mes "n > 0"
} else {
mes "n = 0"
}
}
|
負数の場合は1回の比較で済みます。
ブロックを揃えると広がります。
|
1
2
3
4
5
6
7
8
9
|
-
|
-
|
-
|
!
| #define elsif(%1) else : if %1
n = -1 if (n < 0) {
mes "nは0未満です"
} elsif (n > 0) {
mes "nは0より大きいです"
} else {
mes "nは0です"
}
|
負数の場合は1回の比較で済みます。
ブロックを揃えても広がりません。
|
簡単な条件式の記述例はこのようになります。
1
2
3
4
5
6
7
8
|
| a = 123
mes "a = 123\n-----"
if a = 123 : mes "a = 123"
if a ! 123 : mes "a ! 123"
if a < 10 : mes "a < 10"
if a > 10 : mes "a > 10"
if a <= 123 : mes "a <= 123"
if a >= 123 : mes "a >= 123"
|
このように条件式には数式などを入れて記述します。
これだけ見ると、「条件式」の部分に書いた式が満たされていれば(真)、それ以降の命令を実行する。満たされていない場合(偽)は、次の行に移るように見えます。
本当にそうでしょうか?
次のスクリプトを実行してみてください。
1
2
3
4
5
6
7
8
9
10
11
12
|
| a = 123
if a : mes "a = "+a
a = 1
if a : mes "a = "+a
a = 0
if a : mes "a = "+a
a = -1
if a : mes "a = "+a
if 123 : mes "123"
if 1 : mes "1"
if 0 : mes "0"
if -1 : mes "-1"
|
このスクリプトでは「条件式」には数値しか指定していませんが、エラーが出ることもなく正しく動作しています。
実はHSPのif命令では「条件式」の計算結果の数値が 0 意外であれば、条件を満たすとして以降の命令を実行し、0 であれば次の行に実行を移すようになっています。
if命令の条件式は、比較式と数値の2通りの記述方法があるの?と思われるかもしれませんが、これも違います。
比較式も実は式全体では1個の数値になっているんです。とりあえずサンプルを見てみましょう。
1
2
3
4
5
6
7
|
| a = 123 : mes "a = " + a
mes "条件式:a = 123 → " + (a = 123)
mes "条件式:a ! 123 → " + (a ! 123)
mes "条件式:a < 10 → " + (a < 10)
mes "条件式:a > 10 → " + (a > 10)
mes "条件式:a <= 123 → " + (a <= 123)
mes "条件式:a >= 123 → " + (a >= 123)
|
このように比較演算子(=,!,<,>,<=,>=)で比較している式も、式全体では1個の数値になっていて、if命令ではその数値が0か0意外かを見て動作の分岐を行っています。
これらのことをきちんと理解していれば、次のような書き方の意味も理解できるでしょう。
1
2
3
4
5
6
7
8
|
| a = 16 : b = 1
if a&16 : mes "a&16"
if (a&16) & (b=1) : mes "(a&16) & (b=1)" if ((a&16)!0) & (b=1) : mes "((a&16)!0) & (b=1)"
mes "-----<条件式の結果>-----"
mes "a&16 → " + (a&16)
mes "(a&16) & (b=1) → " + ((a&16) & (b=1))
mes "((a&16)!0) & (b=1) → " + (((a&16)!0) & (b=1))
|
- HspCmd?/if 検索用語を入力 検索フォームを送信 --
- --
- if のブロック対応(大甘)と elsif は関係ないんじゃ? (2つ下の人)
- muzukasisugiru. --
- っこれはすごい -- WIKIWIKI?
- というかこのelsifの『 else:if 』という動作は正式なものなのかたまたまなのか・・・if文のブロックの対応がhsp3.0では甘かったりしてます。 -- kz3
- ハッ。これはその・・・昔書いたやつでして、基本は前菜です。統一化とエラー処理がキモなんですがやってません^^; -- kz3
- この程度なら解るんだけどね〜。 ハハ -- hiroki?
- 書き途中。 -- kz3