こんにちは。
本記事は、@NemesisさんのJavaで湯婆婆を実装してみるという記事の何番か煎じです。
なおかつ、@nakashimaakioさんもKotlinで実装した湯婆婆をAndroidアプリで実装するという記事を投稿されており、ますますもって二番煎じの二番煎じというネスト状態です。
ですが、後者の記事はAndroidアプリにしたがゆえに、コンソール入出力アプリである前者と異なるので、レイアウトリソースファイル(activity_main.xml)も必要だったりOnKeyListenerでイベント処理もしたりと、Android色が強く前に出ています。
※なお、私はAndroidアプリに挑戦されたことを非難しているのではなく、むしろAndroidアプリ大好きな私にとっては実にナイストライ!だと思っております。
そこで私は、同じくKotlin言語を用いますが、コンソール入出力アプリで挑戦してみました。
かつ、このアプリの要件としては、名前の入力が空白だった場合はちゃんとクラッシュ湯婆婆をしなければいけないという仕様も求められているようですので、そこも忠実に守りたいです。
コード
こうなりました。
import java.util.Random
fun main() {
println("契約書だよ。そこに名前を書きな。")
val name = readLine()
println("フン。${name}というのかい。贅沢な名だねぇ。")
val newNameIndex = Random().nextInt(name!!.length)
val newName = name.substring(newNameIndex, newNameIndex + 1)
println("今からお前の名前は${newName}だ。いいかい、${newName}だよ。分かったら返事をするんだ、${newName}!!");
}
実行結果はこちら。
契約書だよ。そこに名前を書きな。
山田太郎
フン。山田太郎というのかい。贅沢な名だねぇ。
今からお前の名前は太だ。いいかい、太だよ。分かったら返事をするんだ、太!!
契約書だよ。そこに名前を書きな。
フン。というのかい。贅沢な名だねぇ。
Exception in thread "main" java.lang.IllegalArgumentException: bound must be positive
at java.base/java.util.Random.nextInt(Random.java:388)
at sample.kotlin.chap01.YubabaKt.main(Yubaba.kt:9)
at sample.kotlin.chap01.YubabaKt.main(Yubaba.kt)
ちゃんとIllegalArgumentExceptionが発生しました。
エラーメッセージ「bound must be positive」のツッコミ箇所がRandom.nextIntであることまでオリジナル記事と一緒です。
まあ、そりゃそうですね。KotlinはJavaと100%互換言語ですから。足並みがそろって当たり前ですね。
そういえば、湯婆婆には、双子の姉「銭婆」がいますね。湯婆婆がJavaなら、銭婆はKotlinかな。声優も両者とも夏木マリが担当した、と言うことで互換性あるし。だなんて無理やり映画にかこつけようとしてみましたが、Kotlinの方が後発なのに姉とはこれ如何に。ムチャしちゃいました。
コードの解説
Javaではjava.util.Scannerを持ち出さなければなりませんでしたが、KotlinはreadLine()という標準関数があるのでラクですね。
それより、気になっていただきたいのが、「!!」演算子です。
Kotlinの公式言語リファレンスによれば、この!!演算子は「NullPointerException愛好家向けだよ(for NPE-lovers)」と皮肉付きで説明されています。
「Null Safty」を標榜するKotlinとしては、この!!演算子は何ともむず痒い存在です。
それもこれも、readLine()関数の戻り値がString?型、つまりNullable(nullかもしれないヨ)オブジェクトをリターンするからです。
nullかもしれない変数だけど、俺はコイツはnullではないと信じたい!!といったカンジでしょうか。
上述で「!!演算子は何ともむず痒い存在」だとは言いましたが、逆に頼もしい存在でもあります。
そこさえ強行突破できちゃえば、以降は「Smart Casts」機能が働くので、次のステップのval newName = name.substring(newNameIndex, newNameIndex + 1)の「name」にはいちいち!!演算子(も、?も)を付けるのが不要となります。
でも、やっぱり!!演算子は嫌だなぁ...と思ったので、次のコードその2をご覧ください。
コードその2
スコープ関数letを使いました。
import java.util.Random
fun main() {
println("契約書だよ。そこに名前を書きな。")
val name = readLine()
println("フン。${name}というのかい。贅沢な名だねぇ。")
val newNameIndex = name?.length?.let { Random().nextInt(it) }
val newName = newNameIndex?.let { name.substring(it, newNameIndex + 1) }
println("今からお前の名前は${newName}だ。いいかい、${newName}だよ。分かったら返事をするんだ、${newName}!!");
}
「Safe Calls」と呼ばれる?.演算子を用いまくってますし、Nullableな変数に立ち向かうときによく使われるスコープ関数letも用いています。
まるで、石橋を叩いて叩いて渡るような慎重さが顕著なコードになりました。
最後に
湯婆婆そのものを楽しむつもりだったんですが、nullに対応することの方が大変だった、という感想です。
あの映画「千と千尋の神隠し」の世界には、nullという概念がそもそも存在するのかな?と思いを馳せてみたら、
あ。
カオナシ???
確かにこいつは、厄介だ。