前回の記事:【Kotlin Koans】はじめるぞ! 第0章 -準備-
メリークリスマス!アスクルの こたにん (@Kotanin0) です。
前回は、Kotlin Koansを解いていくための準備をしました。
ということで、今回からKotlin Koansを実際に解いていきます。
Kotlin Koansは大きく6つの章に分かれています。
- Introduction
- Conventions
- Collections
- Properties
- Builders
- Generics
今回は第1章、 Introduction
を解いていきましょう。
Introductionは全部で12問ありますので、今回はそのうち前半6問を進めます。
本記事ではIntelliJ IDEAでEduToolsを使用して解説します。
Try Kotlinやリポジトリ落とすなど、別の環境でも問題はほぼ同じです。
なんとしても自力で解きたい方、ごめんなさい。
解答を含む記事ですので、自己判断でご覧ください。
また、英語力はそこまで高くないので、独断と偏見のエモい意訳が多々ありますがご容赦ください。
Hello, world!
問題
"OK" という文字列を返却する関数を作ってみましょう!
解答と解説
はじまりのはじまり、 TODO()
となっている部分に解答を書いてくんだよ、っていうチュートリアルです。
今回はシンプルに、関数の返却を書くだけ。
fun start(): String = "OK"
この関数は単一式関数という表現方法になっています。
単一式関数とは、関数の処理部分が単一の式になっている、シンプルに戻り値を返すつくりです。
こうすることで、処理を挟む余地がなくなり、関数の役割が明確になります。
さらに、型推論できる範囲であれば戻り値の型宣言を省略できます。
fun start() = "OK"
素敵。
Java to Kotlin conversion
問題
.java内の関数をコピってKotlinに貼り付けてみましょう。
解答と解説
コピペするだけなので省略。
これはKotlinと親和性の高い IntelliJ IDEA (或いはAndroid Studio) のステマ問題。
Javaから持ってきたコードをKotlinファイル内にペーストするだけで、コードを変換してくれるという便利機能の紹介でした。
Named arguments
問題
Collectionクラスの関数joinToStringを利用してみましょう。
その関数にある、prefix, postfixという引数を、名前付き引数として使ってみましょう。
解答と解説
名前付き引数とは、関数の引数を名前付きで定義しておくことで、関数を利用する側にとても利用しやすくする書き方です。
今回利用した Collection.joinToString には、名前付き引数が6つ用意されています。
fun <T> Array<out T>.joinToString( separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: (T) -> CharSequence = null ): String
今回はこれらのうち prefix
postfix
の2つを指定し、それ以外はデフォルトのままでいけます。
fun joinOptions(options: Collection<String>) = options.joinToString(prefix = "[", postfix = "]")
Default arguments
問題
Javaで書かれたオーバーロードだらけの関数fooがあります。
public String foo(String name, int number, boolean toUpperCase) { return (toUpperCase ? name.toUpperCase() : name) + number; } public String foo(String name, int number) { return foo(name, number, false); } public String foo(String name, boolean toUpperCase) { return foo(name, 42, toUpperCase); } public String foo(String name) { return foo(name, 42); }
Kotlinでは1つの関数に置き換えられるのでやってみましょう。
解答と解説
デフォルト引数とは、関数の引数に初期値を定義しておくことで、同名複数のオーバーライドを減らすことができる書き方です。
今回は引数違いで4つあるJavaのfoo関数を、Kotlinのデフォルト引数を利用して1つにしちゃいましょう。
- name
は使ってそう
- number
はデフォルト 42
でよさそう
- toUpperCase
はデフォルト false
でよさそう
fun foo(name: String, number: Int = 42, toUpperCase: Boolean = false) = (if (toUpperCase) name.toUpperCase() else name) + number
1行で素敵。また単一式関数でスッキリと。
Lambdas
問題
ラムダを使って、Collection内に偶数が含まれているかどうか判定し、その結果を返しましょう。
解答と解説
ラムダとは、「独立して宣言を行わず、式のひとつとして即時利用する関数」みたいなイメージ。
Kotlinのラムダを簡単に表したルールは以下です。
- ラムダ式は、常に中括弧で囲まれています
- パラメータは(もしあれば) ->
の前で宣言されます(パラメータの型を省略してもかまいません)
- 本体が ->
に続きます(存在する場合)
- ラムダの引数が1つの場合、引数の宣言を省略できます。そのときの引数の名前は it
となります。
今回の問題では、Collectionの要素に偶数が含まれているか判定したい、という内容です。
Collectionの中にひとつでも判定したい要素があるかどうかを調べるには、Collections.anyを利用できそうです。
anyは、引数としてBooleanを返す条件式を希望しているようです。
ここでラムダの出番ですね。偶数を判定する式をanyに渡してあげることで今回の問題はクリアです。
fun containsEven(collection: Collection<Int>) = collection.any { it % 2 == 0 }
Strings
問題
日付を表現した文字列 13.06.1992
に対応する正規表現パターンは """\d{2}\.\d{2}\.\d{4}"""
です。
では、13 JUN 1992
(日、スペース、月の省略形、スペース、年)を正規表現を用いて表現しましょう。
解答と解説
文字列リテラルは、ダブルクォート3連発 """
で囲むことで、エスケープが不要になります。
正規表現で ¥d
使いたいときに ¥¥d
にしなくていいし、改行などもそのまま表現することができます。
文字列テンプレートは、文字列内で変数を利用できる記法です。
文字列内でドル記号($
)はじまりで変数名を指定することで、可読性高い文字列のコードが書けます。
名前と年齢を出力したいようなときに、従来の書き方だとこんなかんじ。
"名前=" + member.name + ", 年齢=" + member.age
文字列テンプレートを利用するとこんなかんじ。
"名前=${member.name}, 年齢=${member.age}"
かなり可読性が上がりますね、すごくわかりやすい。
今回の問題は、文字列リテラルと文字列テンプレートを併用するかたちが解答になります。
fun getPattern() = """\d{2}\ $month \d{4}"""
Data classes
問題
Javaで書かれているPersonクラスがあります。
public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
Kotlinのdata classを使って置き換えてみましょう。
解答と解説
データクラスは、シンプルにデータを扱うことに特化した修飾子です。
プライマリコンストラクタとして、classのコンストラクタを明示します。
冗長なコンストラクタを書いたり、フィールド宣言したり、といったコードを不要としてスッキリさせることができます。
今回は、問題に記載のあるJavaコードをコピペすることで、classへの変換は行ってくれます。
(ちょっと前に習ったJava to Kotlinで、一瞬で)
それに data
を付けてあげることでクリアです。
data class Person(val name: String, val age: Int)
第1章 前半戦おわり!
お疲れ様でした。これで第1章 Introduction
の前半6問が終了です!
次回は引き続き、後半6問を解いていこうと思っています。
それでは、また!
ASKULではサーバサイドKotlinを採用しています!
一緒にKotlinを愛でるエンジニアを募集しています!!