SwiftではSwitch構文で文字列が使えるようだが
Objective-CにはObjective-Cの良さがあると思う。C由来のゴタゴタやしがらみ、ややこしさ、汚さをフル活用すれば出来ないことはない・・・と思う。
StackOver風呂でいい記事を見つけた
http://goo.gl/LBeX77
に書いてあるんだが
# define CASE(str) if ([__s__ isEqualToString:(str)])
# define SWITCH(s) for (NSString *__s__ = (s); ; )
# define DEFAULT
SWITCH (string) {
CASE (@"AAA") {
break;
}
CASE (@"BBB") {
break;
}
CASE (@"CCC") {
break;
}
DEFAULT {
break;
}
}
とすればいいらしい。
実際に使ってみたがエレガントだと思う。
簡単にコードを読んでみるとSWITCHがfor文に置き換えられることで、実際のbreakを使えるようにし、なおかつSWITCHで比較元となる文字列を変数にうまく定義している。
改良1
しかし上記のコードだとDEFAULTを書き、なおかつそこでbreakしてやらないとfor文で回り続ける。
これだと実際のswitch構文の仕組みと挙動が異なる。switchとはフォールダウンすることはあっても頭に戻ることはないのだ。
(しかし今回のSWITCHはisEqualToString:をifがその都度確認している為、フォールダウンはできない。何かスマートに実現する方法はないだろうか?)まあC#でもフォールダウンは言語仕様上出来ないから、この件も「仕様」で片付けていいかな・・
なので少し改めてみた。
# define CASE(str) if ([__s__ isEqualToString:(str)])
# define SWITCH(s) for (NSString *__s__ = (s); __s__; __s__ = nil)
# define DEFAULT
こうしておくことで1周し終わればforの継続条件が成り立たなくなり2周目が回ることはないだろう。
改良2
さらに改良1を改良してみる。
しかし改良2は好みが分かれると思う。
# define _STRINGIZE(x) #x
# define __STRINGIZE(text) @ _STRINGIZE(text)
# define CASE(str) if ([__s__ isEqualToString:(__STRINGIZE(str))])
# define SWITCH(s) for (NSString *__s__ = (s); __s__; __s__ = nil)
# define DEFAULT
こうすることで次のような記述が可能になる。
SWITCH (string) {
CASE (AAA) {
break;
}
CASE (BBB) {
break;
}
CASE (CCC) {
break;
}
DEFAULT {
break;
}
}
NSStringを@"AAA"と書かずAAAと記述でき個人的にはブラボーだと思うが、きっとこの辺は好き嫌いがあると思う。
〆
もし良ければIDEにスニペッドの登録を。
# define _STRINGIZE(x) #x
# define __STRINGIZE(text) @ _STRINGIZE(text)
# define CASE(str) if ([__s__ isEqualToString:(__STRINGIZE(str))])
# define SWITCH(s) for (NSString *__s__ = (s); __s__; __s__ = nil)
# define DEFAULT